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 }
navigate('/calendar')
}
return (
<>
Добро пожаловать
Войдите в аккаунт для доступа к панели управления
{/* 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 => (
))}
Уже есть аккаунт?{' '}
)}
{/* ── Step 2: Account ── */}
{step === 2 && (
)}
>
)
}
// ── Page ───────────────────────────────────────────────────────────────────────
export function LoginPage() {
const { user } = useAuth()
const { theme, toggle } = useTheme()
const [mode, setMode] = useState<'login' | 'register'>('login')
if (user) {
return
}
return (
{/* Left panel — branding */}
Современная PMS система
для вашего отеля
Управляйте бронированиями, номерным фондом и уборкой в одном месте.
Синхронизация с Booking.com, Airbnb и другими каналами.
{[
{ value: '500+', label: 'Отелей' },
{ value: '1M+', label: 'Бронирований' },
{ value: '99.9%', label: 'Аптайм' },
].map(s => (
))}
{/* Registration benefits highlight */}
{mode === 'register' && (
{[
'Бесплатный период 14 дней без ввода карты',
'Настройка за 15 минут — импорт из любой PMS',
'Поддержка на русском языке 24/7',
].map(b => (
))}
)}
© 2026 HotelSync · SaaS PMS Platform
{/* Right panel */}
{/* Mobile logo */}
{mode === 'login'
?
setMode('register')} />
: setMode('login')} />
}
)
}