diff --git a/frontend/js/textbook-tracker.js b/frontend/js/textbook-tracker.js index 7422b0b..1cb74cd 100644 --- a/frontend/js/textbook-tracker.js +++ b/frontend/js/textbook-tracker.js @@ -53,7 +53,11 @@ }).catch(() => {}); } - /* ── 2. Initial load: merge server data into local state ──────── */ + /* ── 2. Initial load: merge server data into local state + push back ── + Если в локальном кэше есть ключи, которых нет на сервере + (последствие старого бага syncPending) — досылаем их через + отдельные mark_read POST'ы. Это лечит «вечный 0/N» у пользователей, + которые до фикса уже накликали кучу пилюль. */ function loadServerProgress() { if (typeof LS === 'undefined' || !LS.getToken || !LS.getToken()) return; fetch('/api/textbooks/' + slug, { @@ -62,11 +66,17 @@ .then(r => r.ok ? r.json() : null) .then(d => { if (!d || !d.progress) return; - const merged = Array.from(new Set([...(localState.read || []), ...(d.progress.read || [])])); + const serverRead = new Set(d.progress.read || []); + const localRead = localState.read || []; + const missing = localRead.filter(k => !serverRead.has(k)); + // объединяем для UI + const merged = Array.from(new Set([...localRead, ...d.progress.read || []])); localState.read = merged; if (!localState.last) localState.last = d.progress.last_para; localStorage.setItem(lsKey, JSON.stringify(localState)); refreshAllUI(); + // догоняем сервер последовательно: syncToServer уже коалесцирует + missing.forEach(k => syncToServer({ mark_read: k })); }) .catch(() => {}); }