import { useEffect, useState } from 'react' import { Link, useSearchParams } from 'react-router-dom' import { AlertTriangle, ArrowRight, CheckCircle2, Loader2 } from 'lucide-react' import { AuthLayout } from '@/components/auth/AuthLayout' import { verifyEmail } from '@/api/auth' type VerifyState = 'verifying' | 'success' | 'error' /** * Кэш промисов подтверждения по токену (модульный, вне компонента) — тот же * приём дедупликации, что и у refreshPromise в api/client.ts. Защищает от * повторного POST /auth/verify-email при двойном монтировании эффекта в * React StrictMode (dev): без кэша второй запрос уходит с уже погашенным * токеном и backend отвечает 400 «токен уже использован», хотя первый запрос * уже успешно подтвердил почту. */ const verifyRequests = new Map>() function verifyEmailOnce(token: string): Promise { let request = verifyRequests.get(token) if (!request) { request = verifyEmail(token) verifyRequests.set(token, request) } return request } /** * Экран подтверждения email по ссылке из письма: /verify-email?token=... * (см. design/mockups/auth.html, блок «подтверждение email»). */ export function VerifyEmailPage() { const [searchParams] = useSearchParams() const token = searchParams.get('token') const [state, setState] = useState(token ? 'verifying' : 'error') useEffect(() => { if (!token) return let cancelled = false verifyEmailOnce(token) .then(() => { if (!cancelled) setState('success') }) .catch(() => { if (!cancelled) setState('error') }) return () => { cancelled = true } }, [token]) return (
{state === 'verifying' && (

Проверяем ссылку…

Подтверждаем вашу почту, это займёт пару секунд.

)} {state === 'success' && (

Почта подтверждена

Аккаунт активирован. Теперь доступно бронирование переговорных и вход в конференции.

Перейти ко входу
)} {state === 'error' && (

Ссылка недействительна

Срок действия ссылки истёк или она уже была использована. Запросите письмо ещё раз со страницы регистрации.

Вернуться к регистрации
)}
) }