import { useState, type FormEvent } from 'react' import { Link } from 'react-router-dom' import { useQuery } from '@tanstack/react-query' import { Clock, Mail, Lock, User, Users } from 'lucide-react' import { AuthLayout } from '@/components/auth/AuthLayout' import { getRegistrationOptions, register } from '@/api/auth' import { ApiError, errorDetail } from '@/api/client' /** Текст предупреждения о несовпадении домена почты с эталонными. */ function domainMismatchMessage(domains: string[]): string { const list = domains.map((domain) => `@${domain}`).join(' или ') return `Укажите рабочую почту — регистрация доступна только для домена ${list}` } /** * Экран регистрации (см. design/mockups/auth.html, блок «регистрация»). * Поле «Команда» показывается только если выбор команды включён в * настройках инстанса (`GET /auth/registration-options`, публичный эндпоинт). * Поле «Рабочая почта» дополнительно сверяется с эталонными доменами * (`registration-options.email_domains` — подходит совпадение с ЛЮБЫМ), * если в админке включена верификация по домену — проверка идёт по blur и * при сабмите, backend при включённой верификации и чужом домене отвечает * 400 `invalid_email_domain`. * После успешной регистрации показывает состояние «подтвердите почту» * (письмо со ссылкой backend в dev-режиме печатает в консоль). */ export function RegisterPage() { const [name, setName] = useState('') const [email, setEmail] = useState('') const [password, setPassword] = useState('') const [teamId, setTeamId] = useState('') const [error, setError] = useState(null) const [emailDomainError, setEmailDomainError] = useState(null) const [pending, setPending] = useState(false) const [registeredEmail, setRegisteredEmail] = useState(null) const { data: registrationOptions } = useQuery({ queryKey: ['auth', 'registration-options'], queryFn: getRegistrationOptions, }) const teamChoiceEnabled = registrationOptions?.team_choice_enabled ?? false const teams = registrationOptions?.teams ?? [] const expectedEmailDomains = registrationOptions?.email_domains ?? [] /** Домен после «@» не совпадает (без учёта регистра) ни с одним эталонным — `null`, если сверять не с чем. */ function checkEmailDomain(value: string): string | null { if (expectedEmailDomains.length === 0) return null const atIndex = value.lastIndexOf('@') if (atIndex === -1) return null const domain = value.slice(atIndex + 1).trim().toLowerCase() if (!expectedEmailDomains.some((expected) => domain === expected.toLowerCase())) { return domainMismatchMessage(expectedEmailDomains) } return null } async function handleSubmit(event: FormEvent) { event.preventDefault() setError(null) const domainError = checkEmailDomain(email) setEmailDomainError(domainError) if (domainError) return setPending(true) try { await register({ email, name_user: name, password, team_id: teamChoiceEnabled ? teamId || null : null }) setRegisteredEmail(email) } catch (err) { if (err instanceof ApiError && err.status === 409) { setError('Пользователь с таким email уже зарегистрирован') } else if (err instanceof ApiError && err.status === 400 && errorDetail(err) === 'invalid_email_domain') { setEmailDomainError(expectedEmailDomains.length > 0 ? domainMismatchMessage(expectedEmailDomains) : 'Регистрация с этим доменом почты недоступна') } else { setError('Не удалось зарегистрироваться. Проверьте данные и попробуйте снова') } } finally { setPending(false) } } if (registeredEmail) { return (

Подтвердите почту

Мы отправили письмо со ссылкой на{' '}

Перейти ко входу
) } return (
Вход Регистрация

Создать аккаунт

{emailDomainError &&

{emailDomainError}

}
{teamChoiceEnabled && (
)}
{error ? (

{error}

) : (

Минимум 8 символов, буквы и цифры

)}
) }