From d2cd7632a512d1635694d294c2474641fd5e9339 Mon Sep 17 00:00:00 2001 From: vladtechno Date: Fri, 19 Jun 2026 23:44:57 +1000 Subject: [PATCH] fix(pwa): keep PWA alive during TG login (anchor opens Telegram, app polls on /tg-wait) window.location.href=deep_link navigated the whole PWA to t.me, destroying the /tg-wait polling screen -> the authenticated token was never fetched. Prefetch the pairing session and open Telegram via an (OS app-switch, PWA stays mounted polling); add an Open-Telegram fallback link on the wait screen. Co-Authored-By: claude-flow --- driver-pwa/frontend/src/pages/LoginPage.tsx | 46 +++++++++++++------- driver-pwa/frontend/src/pages/TgWaitPage.tsx | 22 ++++++++-- 2 files changed, 50 insertions(+), 18 deletions(-) diff --git a/driver-pwa/frontend/src/pages/LoginPage.tsx b/driver-pwa/frontend/src/pages/LoginPage.tsx index bb37eb2..b18c215 100644 --- a/driver-pwa/frontend/src/pages/LoginPage.tsx +++ b/driver-pwa/frontend/src/pages/LoginPage.tsx @@ -1,4 +1,4 @@ -import { useState } from "react"; +import { useEffect, useState } from "react"; import { useNavigate } from "react-router-dom"; import { toast } from "sonner"; import { authRequest, authVerify, tgSession } from "@/api/driver"; @@ -15,19 +15,23 @@ export function LoginPage() { const [channel, setChannel] = useState(""); const [busy, setBusy] = useState(false); const [mode, setMode] = useState<"choose" | "code">("choose"); + // Prefetched pairing session so the «Войти через Telegram» control is a real + // the OS opens in Telegram (a synchronous user gesture) WITHOUT + // navigating the PWA away — the app stays mounted on /tg-wait and polls. + const [tg, setTg] = useState<{ pair_session: string; deep_link: string | null } | null>(null); const e164 = "7" + phone; - async function loginViaTelegram() { - setBusy(true); - try { - const r = await tgSession(); - sessionStorage.setItem("pp-pair-session", r.pair_session); - if (r.deep_link) { window.location.href = r.deep_link; } - nav("/tg-wait"); - } catch { - toast.error("Не удалось начать вход. Попробуйте «по коду»."); - setBusy(false); - } + useEffect(() => { + let alive = true; + tgSession().then((r) => { if (alive) setTg(r); }).catch(() => {}); + return () => { alive = false; }; + }, []); + + function startTg() { + if (!tg) return; + sessionStorage.setItem("pp-pair-session", tg.pair_session); + if (tg.deep_link) sessionStorage.setItem("pp-pair-deeplink", tg.deep_link); + nav("/tg-wait"); } async function requestCode() { @@ -75,9 +79,21 @@ export function LoginPage() { {mode === "choose" ? ( <> - + {tg?.deep_link ? ( + + Войти через Telegram + + ) : ( + + )}

Telegram подтвердит ваш номер автоматически.

diff --git a/driver-pwa/frontend/src/pages/TgWaitPage.tsx b/driver-pwa/frontend/src/pages/TgWaitPage.tsx index 35b40a2..dc2d21a 100644 --- a/driver-pwa/frontend/src/pages/TgWaitPage.tsx +++ b/driver-pwa/frontend/src/pages/TgWaitPage.tsx @@ -6,6 +6,7 @@ import { Spinner } from "@/components/Spinner"; export function TgWaitPage() { const nav = useNavigate(); const pairSession = sessionStorage.getItem("pp-pair-session"); + const deepLink = sessionStorage.getItem("pp-pair-deeplink"); const { status } = usePairPoll(pairSession); useEffect(() => { @@ -13,14 +14,29 @@ export function TgWaitPage() { }, [pairSession, nav]); useEffect(() => { - if (status === "authenticated") { sessionStorage.removeItem("pp-pair-session"); nav("/", { replace: true }); } - if (status === "expired") { sessionStorage.removeItem("pp-pair-session"); nav("/login", { replace: true, state: { expired: true } }); } + if (status === "authenticated") { + sessionStorage.removeItem("pp-pair-session"); + sessionStorage.removeItem("pp-pair-deeplink"); + nav("/", { replace: true }); + } + if (status === "expired") { + sessionStorage.removeItem("pp-pair-session"); + sessionStorage.removeItem("pp-pair-deeplink"); + nav("/login", { replace: true, state: { expired: true } }); + } }, [status, nav]); return (

Премиум Водитель

-

Подтвердите номер в Telegram — нажмите «Поделиться номером», затем вернитесь сюда.

+

+ В Telegram нажмите «Поделиться номером для входа», затем вернитесь сюда — вход произойдёт автоматически. +

+ {deepLink && ( + + Открыть Telegram + + )}
);