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 { useNavigate } from "react-router-dom";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { authRequest, authVerify, tgSession } from "@/api/driver";
|
import { authRequest, authVerify, tgSession } from "@/api/driver";
|
||||||
@@ -15,19 +15,23 @@ export function LoginPage() {
|
|||||||
const [channel, setChannel] = useState<string>("");
|
const [channel, setChannel] = useState<string>("");
|
||||||
const [busy, setBusy] = useState(false);
|
const [busy, setBusy] = useState(false);
|
||||||
const [mode, setMode] = useState<"choose" | "code">("choose");
|
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;
|
const e164 = "7" + phone;
|
||||||
|
|
||||||
async function loginViaTelegram() {
|
useEffect(() => {
|
||||||
setBusy(true);
|
let alive = true;
|
||||||
try {
|
tgSession().then((r) => { if (alive) setTg(r); }).catch(() => {});
|
||||||
const r = await tgSession();
|
return () => { alive = false; };
|
||||||
sessionStorage.setItem("pp-pair-session", r.pair_session);
|
}, []);
|
||||||
if (r.deep_link) { window.location.href = r.deep_link; }
|
|
||||||
|
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");
|
nav("/tg-wait");
|
||||||
} catch {
|
|
||||||
toast.error("Не удалось начать вход. Попробуйте «по коду».");
|
|
||||||
setBusy(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function requestCode() {
|
async function requestCode() {
|
||||||
@@ -75,9 +79,21 @@ export function LoginPage() {
|
|||||||
|
|
||||||
{mode === "choose" ? (
|
{mode === "choose" ? (
|
||||||
<>
|
<>
|
||||||
<button className="btn-primary" disabled={busy} onClick={loginViaTelegram}>
|
{tg?.deep_link ? (
|
||||||
{busy ? <Spinner /> : "Войти через Telegram"}
|
<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>
|
</button>
|
||||||
|
)}
|
||||||
<p className="text-muted text-xs mt-3">Telegram подтвердит ваш номер автоматически.</p>
|
<p className="text-muted text-xs mt-3">Telegram подтвердит ваш номер автоматически.</p>
|
||||||
<button className="btn-ghost mt-4" onClick={() => setMode("code")}>Войти по коду</button>
|
<button className="btn-ghost mt-4" onClick={() => setMode("code")}>Войти по коду</button>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { Spinner } from "@/components/Spinner";
|
|||||||
export function TgWaitPage() {
|
export function TgWaitPage() {
|
||||||
const nav = useNavigate();
|
const nav = useNavigate();
|
||||||
const pairSession = sessionStorage.getItem("pp-pair-session");
|
const pairSession = sessionStorage.getItem("pp-pair-session");
|
||||||
|
const deepLink = sessionStorage.getItem("pp-pair-deeplink");
|
||||||
const { status } = usePairPoll(pairSession);
|
const { status } = usePairPoll(pairSession);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -13,14 +14,29 @@ export function TgWaitPage() {
|
|||||||
}, [pairSession, nav]);
|
}, [pairSession, nav]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (status === "authenticated") { sessionStorage.removeItem("pp-pair-session"); nav("/", { replace: true }); }
|
if (status === "authenticated") {
|
||||||
if (status === "expired") { sessionStorage.removeItem("pp-pair-session"); nav("/login", { replace: true, state: { expired: true } }); }
|
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]);
|
}, [status, nav]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="pt-16 text-center">
|
<div className="pt-16 text-center">
|
||||||
<h1 className="text-xl font-extrabold mb-2">Премиум Водитель</h1>
|
<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 />
|
<Spinner />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user