import { useState } from 'react' import { Navigate, useNavigate } from 'react-router-dom' import { Hotel, Eye, EyeOff, Sun, Moon, AlertCircle, Building2, ChevronRight, ChevronLeft, CheckCircle2, User, } from 'lucide-react' import { useAuth } from '../contexts/AuthContext' import { useTheme } from '../contexts/ThemeContext' import { cn } from '../lib/utils' const DEMO_EMAILS = [ 'manager@grand-palace.ru', 'cleaner@grand-palace.ru', 'admin@hotelsync.io', ] type LegalType = 'ooo' | 'ip' | 'ao' | 'pao' | 'other' const LEGAL_TYPES: { id: LegalType; label: string }[] = [ { id: 'ooo', label: 'ООО' }, { id: 'ip', label: 'ИП' }, { id: 'ao', label: 'АО' }, { id: 'pao', label: 'ПАО' }, { id: 'other', label: 'Другое'}, ] // ── Login form ───────────────────────────────────────────────────────────────── function LoginForm({ onSwitch }: { onSwitch: () => void }) { const { login } = useAuth() const navigate = useNavigate() const [email, setEmail] = useState('') const [password, setPassword] = useState('') const [showPass, setShowPass] = useState(false) const [loading, setLoading] = useState(false) const [error, setError] = useState('') const handleSubmit = async (e: React.FormEvent) => { e.preventDefault() setError('') setLoading(true) const loggedIn = await login(email, password) setLoading(false) if (!loggedIn) { setError('Неверный email или пароль'); return } if (loggedIn.role === 'super_admin') navigate('/admin') else navigate('/calendar') } return ( <>

Добро пожаловать

Войдите в аккаунт для доступа к панели управления

setEmail(e.target.value)} required />
setPassword(e.target.value)} required />
{error && (
{error}
)}
{/* Demo hint */}

Демо-аккаунты (пароль: demo):

{DEMO_EMAILS.map(e => ( ))}

Нет аккаунта?{' '}

) } // ── Register form ────────────────────────────────────────────────────────────── function RegisterForm({ onSwitch }: { onSwitch: () => void }) { const [step, setStep] = useState<1 | 2 | 'done'>(1) // Step 1 — Hotel + Legal entity const [hotelName, setHotelName] = useState('') const [legalType, setLegalType] = useState('ooo') const [legalName, setLegalName] = useState('') const [inn, setInn] = useState('') const [kpp, setKpp] = useState('') const [address, setAddress] = useState('') // Step 2 — Account const [firstName, setFirstName] = useState('') const [lastName, setLastName] = useState('') const [email, setEmail] = useState('') const [phone, setPhone] = useState('') const [password, setPassword] = useState('') const [confirm, setConfirm] = useState('') const [showPass, setShowPass] = useState(false) const [showConfirm, setShowConfirm] = useState(false) const [loading, setLoading] = useState(false) const [errors, setErrors] = useState>({}) const isIp = legalType === 'ip' const validateStep1 = () => { const e: Record = {} if (!hotelName.trim()) e.hotelName = 'Введите название отеля' if (!legalName.trim()) e.legalName = 'Введите наименование юрлица' if (!inn.trim()) e.inn = 'Введите ИНН' else if (!/^\d{10,12}$/.test(inn.replace(/\s/g, ''))) e.inn = 'ИНН — 10 цифр (юрлицо) или 12 (ИП)' if (!isIp && !kpp.trim()) e.kpp = 'Введите КПП' setErrors(e) return Object.keys(e).length === 0 } const validateStep2 = () => { const e: Record = {} if (!firstName.trim()) e.firstName = 'Введите имя' if (!lastName.trim()) e.lastName = 'Введите фамилию' if (!email.trim()) e.email = 'Введите email' else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) e.email = 'Некорректный email' if (password.length < 8) e.password = 'Минимум 8 символов' if (password !== confirm) e.confirm = 'Пароли не совпадают' setErrors(e) return Object.keys(e).length === 0 } const nextStep = () => { if (validateStep1()) setStep(2) } const handleSubmit = async (e: React.FormEvent) => { e.preventDefault() if (!validateStep2()) return setLoading(true) // Simulate API call await new Promise(r => setTimeout(r, 1200)) setLoading(false) setStep('done') } const Field = ({ label, error, children, hint, }: { label: string; error?: string; children: React.ReactNode; hint?: string }) => (
{children} {hint && !error &&

{hint}

} {error && (

{error}

)}
) if (step === 'done') { return (

Заявка отправлена!

Мы получили данные отеля {hotelName}.

На адрес {email} отправлено письмо с подтверждением. После проверки данных менеджер HotelSync активирует аккаунт в течение одного рабочего дня.

) } return ( <>

{step === 1 ? 'Регистрация отеля' : 'Данные аккаунта'}

Шаг {step} из 2

{/* Step indicator */}
{[1, 2].map(s => (
{s < step ? : s}
))}
{/* ── Step 1: Hotel + Legal entity ── */} {step === 1 && (
setHotelName(e.target.value)} />

Юридическое лицо

{/* Legal type selector */}
{LEGAL_TYPES.map(lt => ( ))}
setLegalName(e.target.value)} />
setInn(e.target.value.replace(/\D/g, ''))} /> {!isIp && ( setKpp(e.target.value.replace(/\D/g, ''))} /> )}
setAddress(e.target.value)} />

Уже есть аккаунт?{' '}

)} {/* ── Step 2: Account ── */} {step === 2 && (
setFirstName(e.target.value)} /> setLastName(e.target.value)} />
setEmail(e.target.value)} /> setPhone(e.target.value)} />
setPassword(e.target.value)} />
{password && (
{[ password.length >= 8, /[A-Z]/.test(password), /[0-9]/.test(password), ].map((ok, i) => (
))}
)}
setConfirm(e.target.value)} />

Нажимая «Создать аккаунт», вы соглашаетесь с{' '} условиями использования{' '} и{' '} политикой конфиденциальности

)} ) } // ── Page ─────────────────────────────────────────────────────────────────────── export function LoginPage() { const { user } = useAuth() const { theme, toggle } = useTheme() const [mode, setMode] = useState<'login' | 'register'>('login') if (user) { if (user.role === 'super_admin') return return } return (
{/* Left panel — branding */}
HotelSync

Современная PMS система
для вашего отеля

Управляйте бронированиями, номерным фондом и уборкой в одном месте. Синхронизация с Booking.com, Airbnb и другими каналами.

{[ { value: '500+', label: 'Отелей' }, { value: '1M+', label: 'Бронирований' }, { value: '99.9%', label: 'Аптайм' }, ].map(s => (

{s.value}

{s.label}

))}
{/* Registration benefits highlight */} {mode === 'register' && (
{[ 'Бесплатный период 14 дней без ввода карты', 'Настройка за 15 минут — импорт из любой PMS', 'Поддержка на русском языке 24/7', ].map(b => (

{b}

))}
)}

© 2026 HotelSync · SaaS PMS Platform

{/* Right panel */}
{/* Mobile logo */}
HotelSync
{mode === 'login' ? setMode('register')} /> : setMode('login')} /> }
) }