diff --git a/frontend/js/textbook-tracker.js b/frontend/js/textbook-tracker.js index 1cb74cd..fdb8f0b 100644 --- a/frontend/js/textbook-tracker.js +++ b/frontend/js/textbook-tracker.js @@ -214,23 +214,24 @@ localState.read.forEach(k => { refreshPillUI(k); refreshCheckUI(k); }); } - /* ── 7. Pill click → last_para + (первый раз) mark_read ──────── - Объединяем оба обновления в один POST, чтобы syncPending-guard - в syncToServer не дропнул второй вызов в том же тике. */ + /* ── 7. Pill click → ВСЕГДА шлём last_para + mark_read одним POST + Идемпотентно: на сервере `if (!arr.includes(mark_read)) arr.push(...)` + не добавит дубликат. Эта «избыточность» лечит самовосстановлением + ситуации, когда localState.read был засорён старым syncPending-багом + (есть ключ локально, нет на сервере, mark_read иначе никогда не уйдёт). */ function wirePillTracking() { document.body.addEventListener('click', e => { const pill = e.target.closest('.para-pill[data-para]'); if (!pill) return; const key = pill.dataset.para; localState.last = key; - const firstTime = !localState.read.includes(key); - if (firstTime) { + if (!localState.read.includes(key)) { localState.read.push(key); - refreshPillUI(key); - refreshCheckUI(key); } + refreshPillUI(key); + refreshCheckUI(key); persist(); - syncToServer(firstTime ? { mark_read: key } : {}); + syncToServer({ mark_read: key }); }); }