diff --git a/src/App.tsx b/src/App.tsx index e56561c..dc53c49 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -5,7 +5,9 @@ import { ModulesProvider } from './contexts/ModulesContext' import { AmenitiesProvider } from './contexts/AmenitiesContext' import { NotificationsProvider } from './contexts/NotificationsContext' import { AppLayout } from './layouts/AppLayout' +import { CpLayout } from './layouts/CpLayout' import { LoginPage } from './pages/LoginPage' +import { CpLoginPage } from './pages/CpLoginPage' import { CalendarPage } from './pages/CalendarPage' import { BookingsPage } from './pages/BookingsPage' import { RoomsPage } from './pages/RoomsPage' @@ -37,7 +39,42 @@ import { DiscountsPage } from './pages/DiscountsPage' import { GuestReviewPage } from './pages/GuestReviewPage' import { GuestRoomServicePage } from './pages/GuestRoomServicePage' +// Определяем на каком домене работаем +const IS_CP = window.location.hostname === 'cp.hotelsync.ru' + +// ── Guard для CP: если не авторизован → /login ──────────────────────────── +function CpGuard({ children }: { children: React.ReactNode }) { + const auth = localStorage.getItem('cpAuth') + if (!auth) return + return <>{children} +} + export default function App() { + // ── Control Panel (cp.hotelsync.ru) ────────────────────────────────────── + if (IS_CP) { + return ( + + + + } /> + + }> + } /> + } /> + } /> + } /> + } /> + } /> + + + } /> + + + + ) + } + + // ── PMS App (app.hotelsync.ru) ──────────────────────────────────────────── return ( @@ -48,10 +85,10 @@ export default function App() { {/* Public */} } /> - } /> + } /> } /> - {/* App routes */} + {/* PMS routes */} }> } /> } /> @@ -61,17 +98,16 @@ export default function App() { } /> } /> } /> - {/* Module pages */} } /> } /> } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> } /> } /> } /> @@ -83,13 +119,6 @@ export default function App() { } /> - {/* Admin routes */} - }> - } /> - } /> - } /> - - } /> } /> diff --git a/src/layouts/CpLayout.tsx b/src/layouts/CpLayout.tsx new file mode 100644 index 0000000..f2c3077 --- /dev/null +++ b/src/layouts/CpLayout.tsx @@ -0,0 +1,141 @@ +import { useState } from 'react' +import { NavLink, Outlet, useNavigate } from 'react-router-dom' +import { + Building2, Users, BarChart2, CreditCard, Settings, + Shield, LogOut, Menu, X, Bell, Activity, + ChevronRight, +} from 'lucide-react' +import { cn } from '../lib/utils' + +const NAV = [ + { to: '/', icon: BarChart2, label: 'Обзор' }, + { to: '/hotels', icon: Building2, label: 'Отели' }, + { to: '/cp-users', icon: Users, label: 'Пользователи' }, + { to: '/billing', icon: CreditCard, label: 'Тарифы и оплата' }, + { to: '/monitoring', icon: Activity, label: 'Мониторинг' }, + { to: '/cp-settings', icon: Settings, label: 'Настройки' }, +] + +export function CpLayout() { + const navigate = useNavigate() + const [open, setOpen] = useState(false) + + const stored = localStorage.getItem('cpAuth') + const admin = stored ? JSON.parse(stored) : null + + const logout = () => { + localStorage.removeItem('cpAuth') + navigate('/login', { replace: true }) + } + + return ( +
+ {/* Mobile overlay */} + {open && ( +
setOpen(false)} + /> + )} + + {/* Sidebar */} + + + {/* Main area */} +
+ {/* Topbar */} +
+ + + {/* Breadcrumb placeholder */} +
+ cp.hotelsync.ru + + Control Panel +
+ +
+ {/* Status indicator */} +
+ + Система в норме +
+ + +
+
+ + {/* Page content */} +
+ +
+
+
+ ) +} diff --git a/src/pages/CpLoginPage.tsx b/src/pages/CpLoginPage.tsx new file mode 100644 index 0000000..3c0a169 --- /dev/null +++ b/src/pages/CpLoginPage.tsx @@ -0,0 +1,144 @@ +import { useState, FormEvent } from 'react' +import { useNavigate } from 'react-router-dom' +import { Eye, EyeOff, Shield, AlertCircle } from 'lucide-react' +import { cn } from '../lib/utils' + +const ADMIN_EMAIL = 'admin@hotelsync.io' +const ADMIN_PASSWORD = 'demo' + +export function CpLoginPage() { + const navigate = useNavigate() + const [email, setEmail] = useState('') + const [password, setPassword] = useState('') + const [showPass, setShowPass] = useState(false) + const [error, setError] = useState('') + const [loading, setLoading] = useState(false) + + const handleSubmit = async (e: FormEvent) => { + e.preventDefault() + setError('') + setLoading(true) + + await new Promise(r => setTimeout(r, 600)) + + if (email.trim() === ADMIN_EMAIL && password === ADMIN_PASSWORD) { + localStorage.setItem('cpAuth', JSON.stringify({ email, ts: Date.now() })) + navigate('/', { replace: true }) + } else { + setError('Неверный email или пароль') + } + setLoading(false) + } + + return ( +
+ {/* Subtle grid background */} +
+ +
+ {/* Logo */} +
+
+ +
+

HotelSync

+

Control Panel · Только для команды

+
+ + {/* Card */} +
+
+ {/* Email */} +
+ + { setEmail(e.target.value); setError('') }} + /> +
+ + {/* Password */} +
+ +
+ { setPassword(e.target.value); setError('') }} + /> + +
+
+ + {/* Error */} + {error && ( +
+ +

{error}

+
+ )} + + {/* Submit */} + +
+
+ +

+ Доступ только для сотрудников HotelSync Inc. +

+
+
+ ) +}