fix: sticker toggle disabled state reactivity and pulse edge case

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-23 17:14:14 -04:00
parent cea0e8c2be
commit ab973cbf4f

View File

@@ -34,14 +34,19 @@ function Picker() {
const [sessionEnded, setSessionEnded] = useState(false); const [sessionEnded, setSessionEnded] = useState(false);
const [stickerMode, setStickerMode] = useState('auto'); const [stickerMode, setStickerMode] = useState('auto');
const stickerSendRef = useRef(null); const stickerSendRef = useRef(null);
const [stickerWsReady, setStickerWsReady] = useState(false);
const [stickerPulse, setStickerPulse] = useState(false); const [stickerPulse, setStickerPulse] = useState(false);
const prevStickerModeRef = useRef(stickerMode); const prevStickerModeRef = useRef(stickerMode);
useEffect(() => { useEffect(() => {
if (stickerMode === 'auto' && prevStickerModeRef.current !== 'auto') { if (stickerMode === 'auto' && prevStickerModeRef.current !== 'auto') {
setStickerPulse(true); setStickerPulse(true);
const timer = setTimeout(() => setStickerPulse(false), 2000); const timer = setTimeout(() => setStickerPulse(false), 2000);
prevStickerModeRef.current = stickerMode;
return () => clearTimeout(timer); return () => clearTimeout(timer);
} }
if (stickerMode !== 'auto') {
setStickerPulse(false);
}
prevStickerModeRef.current = stickerMode; prevStickerModeRef.current = stickerMode;
}, [stickerMode]); }, [stickerMode]);
@@ -905,7 +910,7 @@ function Picker() {
setStickerMode(opt.value); setStickerMode(opt.value);
stickerSendRef.current?.(opt.value); stickerSendRef.current?.(opt.value);
}} }}
disabled={!stickerSendRef.current} disabled={!stickerWsReady}
className={`px-3 py-1.5 text-xs font-medium transition ${ className={`px-3 py-1.5 text-xs font-medium transition ${
i === 1 ? 'border-x border-gray-300 dark:border-gray-600 ' : '' i === 1 ? 'border-x border-gray-300 dark:border-gray-600 ' : ''
}${ }${
@@ -913,7 +918,7 @@ function Picker() {
? opt.activeClass ? opt.activeClass
: 'bg-white dark:bg-gray-700 text-gray-700 dark:text-gray-300' : 'bg-white dark:bg-gray-700 text-gray-700 dark:text-gray-300'
}${ }${
!stickerSendRef.current ? ' opacity-50 cursor-not-allowed' : '' !stickerWsReady ? ' opacity-50 cursor-not-allowed' : ''
}`} }`}
> >
{opt.label} {opt.label}
@@ -1346,6 +1351,7 @@ function Picker() {
setGameSource={setGameSource} setGameSource={setGameSource}
setStickerMode={setStickerMode} setStickerMode={setStickerMode}
stickerSendRef={stickerSendRef} stickerSendRef={stickerSendRef}
setStickerWsReady={setStickerWsReady}
/> />
</div> </div>
</div> </div>
@@ -1353,7 +1359,7 @@ function Picker() {
); );
} }
function SessionInfo({ sessionId, onGamesUpdate, playingGame, setPlayingGame, setHasPlayedGames, setLeadingGame, setPollActive, pollActiveRef, setPollResult, setPollEndingAt, setShowEndPollOptions, pollStartedAtRef, setSelectedGame, setGameSource, setStickerMode, stickerSendRef }) { function SessionInfo({ sessionId, onGamesUpdate, playingGame, setPlayingGame, setHasPlayedGames, setLeadingGame, setPollActive, pollActiveRef, setPollResult, setPollEndingAt, setShowEndPollOptions, pollStartedAtRef, setSelectedGame, setGameSource, setStickerMode, stickerSendRef, setStickerWsReady }) {
const { isAuthenticated, token } = useAuth(); const { isAuthenticated, token } = useAuth();
const [games, setGames] = useState([]); const [games, setGames] = useState([]);
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
@@ -1450,6 +1456,7 @@ function SessionInfo({ sessionId, onGamesUpdate, playingGame, setPlayingGame, se
ws.send(JSON.stringify({ type: 'stickers.setMode', data: { mode } })); ws.send(JSON.stringify({ type: 'stickers.setMode', data: { mode } }));
} }
}; };
setStickerWsReady(true);
return; return;
} }
@@ -1552,6 +1559,7 @@ function SessionInfo({ sessionId, onGamesUpdate, playingGame, setPlayingGame, se
console.log('[WebSocket] Disconnected, reconnecting in 3s...'); console.log('[WebSocket] Disconnected, reconnecting in 3s...');
clearInterval(pingIntervalRef.current); clearInterval(pingIntervalRef.current);
stickerSendRef.current = null; stickerSendRef.current = null;
setStickerWsReady(false);
reconnectTimeoutRef.current = setTimeout(connectWs, 3000); reconnectTimeoutRef.current = setTimeout(connectWs, 3000);
}; };
@@ -1560,7 +1568,7 @@ function SessionInfo({ sessionId, onGamesUpdate, playingGame, setPlayingGame, se
console.error('[WebSocket] Failed to connect:', error); console.error('[WebSocket] Failed to connect:', error);
reconnectTimeoutRef.current = setTimeout(connectWs, 3000); reconnectTimeoutRef.current = setTimeout(connectWs, 3000);
} }
}, [sessionId, token, loadGames, setPollActive, setPollResult, setPollEndingAt, setShowEndPollOptions, setLeadingGame, pollActiveRef, pollStartedAtRef, setSelectedGame, setGameSource, setStickerMode, stickerSendRef]); }, [sessionId, token, loadGames, setPollActive, setPollResult, setPollEndingAt, setShowEndPollOptions, setLeadingGame, pollActiveRef, pollStartedAtRef, setSelectedGame, setGameSource, setStickerMode, stickerSendRef, setStickerWsReady]);
useEffect(() => { useEffect(() => {
connectWs(); connectWs();
@@ -1568,6 +1576,7 @@ function SessionInfo({ sessionId, onGamesUpdate, playingGame, setPlayingGame, se
return () => { return () => {
clearTimeout(reconnectTimeoutRef.current); clearTimeout(reconnectTimeoutRef.current);
clearInterval(pingIntervalRef.current); clearInterval(pingIntervalRef.current);
setStickerWsReady(false);
if (wsRef.current) { if (wsRef.current) {
wsRef.current.onclose = null; wsRef.current.onclose = null;
wsRef.current.close(); wsRef.current.close();