import { useEffect, useState } from "react"; import { useNavigate } from "react-router-dom"; import { toast } from "sonner"; import { authRequest, authVerify, tgSession } from "@/api/driver"; import { digitsOnly, formatPhone } from "@/lib/format"; import { useAuth } from "@/store/auth"; import { Spinner } from "@/components/Spinner"; export function LoginPage() { const nav = useNavigate(); const setSession = useAuth((s) => s.setSession); const [phone, setPhone] = useState(""); // national 10 digits const [code, setCode] = useState(""); const [step, setStep] = useState<"phone" | "code">("phone"); 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; 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() { if (phone.length < 10) return; setBusy(true); try { const r = await authRequest(e164); if (r.status === "onboarding") { sessionStorage.setItem("pp-onboarding", JSON.stringify({ ...r.deep_links, phone })); nav("/onboarding"); return; } setChannel(r.channel); setStep("code"); } catch (err: unknown) { const status = (err as { response?: { status?: number } })?.response?.status; const msg = status === 404 ? "Номер не найден. Обратитесь в парк." : status === 429 ? "Слишком часто. Попробуйте позже." : "Не удалось отправить код"; toast.error(msg); } finally { setBusy(false); } } async function verify() { if (code.length < 4) return; setBusy(true); try { const r = await authVerify(e164, code); setSession(r.token, r.driver_id); nav("/"); } catch { toast.error("Неверный или просроченный код"); } finally { setBusy(false); } } return (

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

Вход в приложение

{mode === "choose" ? ( <> {tg?.deep_link ? (
Войти через Telegram ) : ( )}

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

) : ( <> {step === "phone" ? ( <> setPhone(digitsOnly(e.target.value).replace(/^7/, "").slice(0, 10))} className="card w-full px-4 py-3 mb-3 text-base bg-white" />

Код придёт в Telegram или MAX.

) : ( <>

Код отправлен в {channel === "max" ? "MAX" : "Telegram"}.

setCode(digitsOnly(e.target.value).slice(0, 6))} className="card w-full px-4 py-3 mb-3 text-base tracking-widest bg-white" /> )} )}
); }