'use client'; import { useState, useEffect, useRef, useCallback } from 'react'; import { useRouter, useSearchParams } from 'next/navigation'; import { register } from '@/api/auth'; import { REFERRAL_STORAGE_KEY } from '@/api/referrals'; import { searchCitiesFromCSV, type CityOption } from '@/api/profile'; import { getErrorMessage } from '@/lib/error-utils'; const loadMaterialComponents = async () => { await Promise.all([ import('@material/web/textfield/filled-text-field.js'), import('@material/web/button/filled-button.js'), import('@material/web/button/text-button.js'), import('@material/web/checkbox/checkbox.js'), import('@material/web/select/filled-select.js'), import('@material/web/select/select-option.js'), ]); }; const ROLE_OPTIONS: { value: 'mentor' | 'client' | 'parent'; label: string }[] = [ { value: 'mentor', label: 'Ментор' }, { value: 'client', label: 'Студент' }, { value: 'parent', label: 'Родитель' }, ]; export default function RegisterPage() { const router = useRouter(); const searchParams = useSearchParams(); const [firstName, setFirstName] = useState(''); const [lastName, setLastName] = useState(''); const [city, setCity] = useState(''); const [citySearchResults, setCitySearchResults] = useState([]); const [isCityInputFocused, setIsCityInputFocused] = useState(false); const [isSearchingCities, setIsSearchingCities] = useState(false); const [timezoneOverride, setTimezoneOverride] = useState(null); const [role, setRole] = useState<'mentor' | 'client' | 'parent'>('client'); const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const [confirmPassword, setConfirmPassword] = useState(''); const [referralCode, setReferralCode] = useState(''); const [showReferralField, setShowReferralField] = useState(false); const [consent, setConsent] = useState(false); const [loading, setLoading] = useState(false); const [error, setError] = useState(''); const [registrationSuccess, setRegistrationSuccess] = useState(false); const [registeredEmail, setRegisteredEmail] = useState(''); const [componentsLoaded, setComponentsLoaded] = useState(false); const roleSelectRef = useRef(null); // Реферальный код: при открытии — из URL ?ref= или из localStorage useEffect(() => { if (typeof window === 'undefined') return; const refFromUrl = searchParams.get('ref')?.trim() || ''; if (refFromUrl) { localStorage.setItem(REFERRAL_STORAGE_KEY, refFromUrl); setReferralCode(refFromUrl); setShowReferralField(true); return; } const fromLs = localStorage.getItem(REFERRAL_STORAGE_KEY) || ''; if (fromLs) { setReferralCode(fromLs); setShowReferralField(true); } }, [searchParams]); useEffect(() => { const el = roleSelectRef.current; if (el && role) el.value = role; }, [role, componentsLoaded]); useEffect(() => { loadMaterialComponents() .then(() => setComponentsLoaded(true)) .catch((err) => { console.error('Error loading Material components:', err); setComponentsLoaded(true); }); }, []); const getTimezoneForSubmit = () => { if (timezoneOverride) return timezoneOverride; if (typeof Intl !== 'undefined' && Intl.DateTimeFormat) { return Intl.DateTimeFormat().resolvedOptions().timeZone; } return 'Europe/Moscow'; }; const handleCitySearch = useCallback(async (query: string) => { if (query.trim().length < 2) { setCitySearchResults([]); return; } setIsSearchingCities(true); try { const results = await searchCitiesFromCSV(query.trim(), 20); setCitySearchResults(results); } catch { setCitySearchResults([]); } finally { setIsSearchingCities(false); } }, []); useEffect(() => { const t = setTimeout(() => { if (city.trim().length >= 2) handleCitySearch(city); else setCitySearchResults([]); }, 300); return () => clearTimeout(t); }, [city, handleCitySearch]); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); setLoading(true); setError(''); if (!consent) { setError('Необходимо согласие на обработку персональных данных'); setLoading(false); return; } if (password !== confirmPassword) { setError('Пароли не совпадают'); setLoading(false); return; } try { await register({ email, password, password_confirm: confirmPassword, first_name: firstName, last_name: lastName, role, city: city.trim(), timezone: getTimezoneForSubmit(), }); // Не авторизуем сразу — требуется подтверждение email setRegisteredEmail(email); setRegistrationSuccess(true); return; } catch (err: any) { setError(getErrorMessage(err, 'Ошибка регистрации. Проверьте данные.')); } finally { setLoading(false); } }; if (!componentsLoaded) { return (
); } if (registrationSuccess) { return (

Регистрация

На адрес {registeredEmail} отправлено письмо с ссылкой для подтверждения.

Перейдите по ссылке из письма, затем войдите в аккаунт.

router.push('/login')} style={{ width: '100%', height: '48px', fontSize: '16px', fontWeight: '500', }} > Вернуться ко входу
); } return (

Регистрация

setFirstName(e.target.value || '')} required style={{ width: '100%' }} /> setLastName(e.target.value || '')} required style={{ width: '100%' }} />
setCity(e.target.value)} onFocus={() => { setIsCityInputFocused(true); if (city.trim().length >= 2) handleCitySearch(city); }} onBlur={() => setTimeout(() => setIsCityInputFocused(false), 200)} placeholder="Введите город" autoComplete="off" required style={{ width: '100%', padding: '14px 16px', borderRadius: 12, border: '1px solid var(--md-sys-color-outline, #E6E6E6)', background: 'var(--md-sys-color-surface-container-highest, #f5f5f5)', fontSize: 16, color: 'var(--md-sys-color-on-surface, #1a1a1a)', boxSizing: 'border-box', }} /> {isSearchingCities && (
)}
{isCityInputFocused && citySearchResults.length > 0 && (
{citySearchResults.map((cityOpt, idx) => ( ))}
)}
{ const v = (e.target?.value ?? '') as string; if (v === 'mentor' || v === 'client' || v === 'parent') setRole(v); }} required style={{ width: '100%' }} > {ROLE_OPTIONS.map((opt) => ( {opt.label} ))}
setEmail(e.target.value || '')} required style={{ width: '100%' }} />
setPassword(e.target.value || '')} required style={{ width: '100%' }} />
setConfirmPassword(e.target.value || '')} required style={{ width: '100%' }} />
{/* Реферальный код — сворачиваемый блок */}
{ const v = (e.target?.value ?? '') as string; setReferralCode(v); if (typeof window !== 'undefined') localStorage.setItem(REFERRAL_STORAGE_KEY, v); }} style={{ width: '100%' }} />
setConsent(!!e.target?.checked)} style={{ flexShrink: 0, marginTop: '4px' }} />
{error && (
{error}
)} {loading ? 'Регистрация...' : 'Зарегистрироваться'}
router.push('/login')} style={{ fontSize: '14px' }}> Уже есть аккаунт? Войти
); }