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 <a href> (OS app-switch, PWA stays
mounted polling); add an Open-Telegram fallback link on the wait screen.

Co-Authored-By: claude-flow <ruv@ruv.net>
This commit is contained in:
2026-06-19 23:44:57 +10:00
co-authored by claude-flow
parent 5ab4e9e74e
commit d2cd7632a5
2 changed files with 50 additions and 18 deletions
+31 -15
View File
@@ -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<string>("");
const [busy, setBusy] = useState(false);
const [mode, setMode] = useState<"choose" | "code">("choose");
// Prefetched pairing session so the «Войти через Telegram» control is a real
// <a href> 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" ? (
<>
<button className="btn-primary" disabled={busy} onClick={loginViaTelegram}>
{busy ? <Spinner /> : "Войти через Telegram"}
</button>
{tg?.deep_link ? (
<a
href={tg.deep_link}
target="_blank"
rel="noopener noreferrer"
className="btn-primary block text-center"
onClick={startTg}
>
Войти через Telegram
</a>
) : (
<button className="btn-primary" disabled>
<Spinner />
</button>
)}
<p className="text-muted text-xs mt-3">Telegram подтвердит ваш номер автоматически.</p>
<button className="btn-ghost mt-4" onClick={() => setMode("code")}>Войти по коду</button>
</>