Surface reading-plan pull failures too, fix StrictMode false sync
Build and Push Docker Image / build-and-push (push) Failing after 21s

The sign-in pull (GET /api/reading-plans -> merge) had the same silent-
failure gap the push side had before the last fix: a failed fetch just
left local state as-is with zero indication anything was wrong. Moved it
into the hook as pullServerReadingProgress(), which reports failures
through the same error banner/retry the push path already uses.

Also found and fixed a real bug while testing this: the "skip syncing on
the very first render" guard used a boolean ref, which React 18 StrictMode
defeats by double-invoking effects in dev — the second invocation saw the
flag already flipped and fired a spurious sync of stale localStorage data
before the app had even confirmed sign-in, occasionally producing a false
"couldn't sync" banner on fresh loads. Replaced it with a reference-equality
check against the state object captured at mount, which both of
StrictMode's synthetic invocations see identically. Caught this in
useReadingPlans.js's own test run, not manual testing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
nmemmertandClaude Sonnet 5 committed 2026-09-23 14:47:51 -04:00
1 parent b14dbb52cc
commit 986d2e9331
2 files changed
+38 -11

No files matched your search

+5 -5
View File
@@ -7,7 +7,7 @@ import { useProjectLibrary } from './hooks/useProjectLibrary.js';
import { useReadingPlans } from './hooks/useReadingPlans.js';
import { useSharedView } from './hooks/useSharedView.js';
import HomePage from './pages/HomePage.jsx';
import { getRemoteReadingProgress, saveRemoteProject } from './syncService.js';
import { saveRemoteProject } from './syncService.js';
import {
bookOptions, buildExportHtml, loadProjectIndex, makeId, parseBibleChapter, switchStorageUser,
} from './utils/bibleUtils.jsx';
@@ -49,10 +49,10 @@ const App = () => {
.then((r) => r.ok ? r.json() : null)
.then((serverInk) => { if (serverInk) reader.mergeServerInk(serverInk); })
.catch(() => {});
// Same for reading plan progress
getRemoteReadingProgress().then((result) => {
if (result.ok) readingPlans.mergeServerReadingProgress(result.data);
});
// Same for reading plan progress — pullServerReadingProgress surfaces
// a failed GET via the same error banner a failed push uses, instead
// of silently leaving stale/empty local state in place.
readingPlans.pullServerReadingProgress();
},
onSignOut: () => {
setProjectIndex(switchStorageUser(null));