From 36a81a05ec58320ee89310b1f2fb9f969a231504 Mon Sep 17 00:00:00 2001 From: root Date: Thu, 20 Aug 2026 21:52:52 +0000 Subject: [PATCH] Fix: debounce login + try/catch TG.showAlert MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - emailLogin: защита от двойного клика (_loginInProgress) - api(): timeout 20s + cache:'no-store' + redirect:'follow' - tg.js: try/catch вокруг showAlert/showConfirm (WebAppMethodUnsupported fix) --- public/js/api.js | 12 +++++++++--- public/js/app.js | 4 ++++ public/js/tg.js | 16 ++++++++++++---- 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/public/js/api.js b/public/js/api.js index 68bc4cc..841eb1e 100644 --- a/public/js/api.js +++ b/public/js/api.js @@ -58,13 +58,19 @@ async function api(path, opts = {}, _retry = 0) { o.body = JSON.stringify(o.body); } let r; - // timeout 15s — иначе UI висит вечно + // timeout 20s const controller = new AbortController(); - const tid = setTimeout(() => controller.abort(), 15000); + const tid = setTimeout(() => controller.abort(), 20000); const t0 = Date.now(); try { // credentials:'include' — браузер шлёт cookies (HttpOnly buhapp_at) - r = await fetch(API_BASE + path, { ...o, credentials: 'include', signal: controller.signal }); + r = await fetch(API_BASE + path, { + ...o, + credentials: 'include', + signal: controller.signal, + cache: 'no-store', + redirect: 'follow', + }); } catch (networkErr) { clearTimeout(tid); const ms = Date.now() - t0; diff --git a/public/js/app.js b/public/js/app.js index 95c2aa0..7100a3b 100644 --- a/public/js/app.js +++ b/public/js/app.js @@ -243,6 +243,8 @@ const App = { }, async emailLogin() { + if (this._loginInProgress) return; // защита от двойного клика + this._loginInProgress = true; const email = document.getElementById('el-email').value.trim(); const pass = document.getElementById('el-pass').value; const btn = document.getElementById('el-login'); @@ -260,6 +262,8 @@ const App = { if (hint) { hint.textContent = '⚠️ ' + e.message; hint.style.color = 'var(--danger)'; } TG_APP.showAlert('Ошибка входа: ' + e.message); if (btn) { btn.disabled = false; btn.textContent = 'Войти'; } + } finally { + this._loginInProgress = false; } }, diff --git a/public/js/tg.js b/public/js/tg.js index 22c8aa6..b12d200 100644 --- a/public/js/tg.js +++ b/public/js/tg.js @@ -21,12 +21,20 @@ window.TG_APP = { } catch (e) {} }, showAlert: (msg) => { - if (TG?.showAlert) TG.showAlert(msg); - else alert(msg); + try { + if (TG?.showAlert) TG.showAlert(String(msg)); + else alert(String(msg)); + } catch (e) { + try { alert(String(msg)); } catch {} + } }, showConfirm: (msg) => { - if (TG?.showConfirm) return new Promise((r) => TG.showConfirm(msg, r)); - return Promise.resolve(confirm(msg)); + try { + if (TG?.showConfirm) return new Promise((r) => TG.showConfirm(msg, r)); + return Promise.resolve(confirm(String(msg))); + } catch (e) { + try { return Promise.resolve(confirm(String(msg))); } catch { return Promise.resolve(false); } + } }, theme: () => TG?.themeParams || {},