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:
@@ -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>
|
||||
</>
|
||||
|
||||
@@ -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 (
|
||||
<div className="pt-16 text-center">
|
||||
<h1 className="text-xl font-extrabold mb-2">Премиум Водитель</h1>
|
||||
<p className="text-muted text-sm mb-8">Подтвердите номер в Telegram — нажмите «Поделиться номером», затем вернитесь сюда.</p>
|
||||
<p className="text-muted text-sm mb-6">
|
||||
В Telegram нажмите «Поделиться номером для входа», затем вернитесь сюда — вход произойдёт автоматически.
|
||||
</p>
|
||||
{deepLink && (
|
||||
<a href={deepLink} target="_blank" rel="noopener noreferrer" className="btn-primary block text-center mb-6">
|
||||
Открыть Telegram
|
||||
</a>
|
||||
)}
|
||||
<Spinner />
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user