From 79ac1b0659204a210a2ac3c5befcdb792e962848 Mon Sep 17 00:00:00 2001 From: Tetardtek Date: Tue, 24 Mar 2026 14:43:58 +0100 Subject: [PATCH] =?UTF-8?q?feat:=20multi-tab=20sync=20=E2=80=94=20save=20o?= =?UTF-8?q?n=20blur,=20reload=20from=20server=20on=20focus?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - On blur: immediate save to server (no 30s wait) - On focus: fetch server save, load if newer than local - Handles multi-browser scenario (laptop → desktop) --- Frontend/src/hooks/useSaveSync.ts | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/Frontend/src/hooks/useSaveSync.ts b/Frontend/src/hooks/useSaveSync.ts index 0114d41..80fc8c2 100644 --- a/Frontend/src/hooks/useSaveSync.ts +++ b/Frontend/src/hooks/useSaveSync.ts @@ -89,6 +89,36 @@ export function useSaveSync({ getGameState, onLoad, playTimeSeconds }: SaveSyncO return () => clearInterval(interval); }, [saveToServer, user]); + // Reload from server on tab focus (multi-tab/multi-browser sync) + useEffect(() => { + if (!user) return undefined; + + const handleFocus = () => { + apiRequest("/save").then((data) => { + if (data?.gameState && data.lastSave) { + // Only load if server save is newer than our last known save + if (!lastSaveRef.current || new Date(data.lastSave) > new Date(lastSaveRef.current)) { + onLoad(data.gameState); + lastSaveRef.current = data.lastSave; + console.info("[SaveSync] Reloaded from server on focus"); + } + } + }); + }; + + const handleBlur = () => { + saveToServer(); + console.info("[SaveSync] Saved on blur — other tabs will get latest"); + }; + + window.addEventListener("focus", handleFocus); + window.addEventListener("blur", handleBlur); + return () => { + window.removeEventListener("focus", handleFocus); + window.removeEventListener("blur", handleBlur); + }; + }, [user, onLoad]); + // Save on page unload useEffect(() => { const handleUnload = () => {