- Merge handleOnline and the shared branch of handleVisibilityChange into a
single handleReturn function. visibilitychange is now a thin guard that calls
it only on show. Both events share the same logic: reconnect if socket dropped,
or restore UI state + rejoin room + revalidate if the socket survived.
- Remove setIsReconnecting(false) from connect_error: reconnect_attempt fires
immediately after and resets it to true anyway, causing the "Reconnecting"
overlay to flicker off and back on during every retry cycle.
https://claude.ai/code/session_016tCZVFjSeHdQsdKktbDHEt
Mobile browsers suspend JavaScript and silently drop WebSocket connections
when the user switches to another app, without firing "offline"/"online"
events. Add a visibilitychange handler so that when the user returns:
- If the socket is disconnected, reconnect immediately (skipping backoff)
- If the socket appears connected but JS was suspended, rejoin the draft
room and trigger a loader revalidation to catch any missed picks/state
https://claude.ai/code/session_016tCZVFjSeHdQsdKktbDHEt
- Reduce ping detection window from ~45s to ~15s (pingTimeout 5s, pingInterval 10s)
- Listen to window offline/online events for instant UI feedback on network drop
- Force immediate reconnect on online event instead of waiting for backoff
- Fix stuck-reconnecting bug when network returns within ping timeout window
- Wrap on/off/emit in useCallback to prevent listener re-registration every second
- Expose reconnectCount to trigger revalidator.revalidate() after each reconnect
- Reset hasConnectedOnce ref per socket instance to avoid spurious revalidations
- Remove stale socket ref from hook return value; add emit helper instead
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>