BookingModal: move guest fields to right column; Theme: auto mode follows system prefers-color-scheme
This commit is contained in:
@@ -450,7 +450,12 @@ export function BookingModal({ open, draft, rooms, bookings = [], onClose, onSav
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* 3. ФИО гостя */}
|
||||
</div>
|
||||
|
||||
{/* ── RIGHT COLUMN ── */}
|
||||
<div className="flex-1 space-y-4 min-w-0">
|
||||
|
||||
{/* Гость */}
|
||||
<div>
|
||||
<label className="block text-sm font-semibold text-slate-700 dark:text-slate-300 mb-2">
|
||||
Гость
|
||||
@@ -499,45 +504,38 @@ export function BookingModal({ open, draft, rooms, bookings = [], onClose, onSav
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 4. Взрослые / Дети / Статус */}
|
||||
<div className="grid grid-cols-3 gap-2">
|
||||
<div>
|
||||
<label className="block text-xs text-slate-500 dark:text-slate-400 mb-1">Взрослых</label>
|
||||
<input
|
||||
type="number" min={1} max={room?.maxGuests ?? 6} className="input"
|
||||
value={form.adults}
|
||||
onChange={e => set('adults', parseInt(e.target.value) || 1)}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-xs text-slate-500 dark:text-slate-400 mb-1">Детей</label>
|
||||
<input
|
||||
type="number" min={0} max={4} className="input"
|
||||
value={form.children}
|
||||
onChange={e => set('children', parseInt(e.target.value) || 0)}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-xs text-slate-500 dark:text-slate-400 mb-1">Статус</label>
|
||||
<select
|
||||
className="input"
|
||||
value={form.status}
|
||||
onChange={e => set('status', e.target.value as BookingStatus)}
|
||||
>
|
||||
{(Object.entries(BOOKING_STATUS_LABELS) as [BookingStatus, string][]).map(([k, v]) => (
|
||||
<option key={k} value={k}>{v}</option>
|
||||
))}
|
||||
</select>
|
||||
<div className="grid grid-cols-3 gap-2 mt-2">
|
||||
<div>
|
||||
<label className="block text-xs text-slate-500 dark:text-slate-400 mb-1">Взрослых</label>
|
||||
<input
|
||||
type="number" min={1} max={room?.maxGuests ?? 6} className="input"
|
||||
value={form.adults}
|
||||
onChange={e => set('adults', parseInt(e.target.value) || 1)}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-xs text-slate-500 dark:text-slate-400 mb-1">Детей</label>
|
||||
<input
|
||||
type="number" min={0} max={4} className="input"
|
||||
value={form.children}
|
||||
onChange={e => set('children', parseInt(e.target.value) || 0)}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-xs text-slate-500 dark:text-slate-400 mb-1">Статус</label>
|
||||
<select
|
||||
className="input"
|
||||
value={form.status}
|
||||
onChange={e => set('status', e.target.value as BookingStatus)}
|
||||
>
|
||||
{(Object.entries(BOOKING_STATUS_LABELS) as [BookingStatus, string][]).map(([k, v]) => (
|
||||
<option key={k} value={k}>{v}</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{/* ── RIGHT COLUMN ── */}
|
||||
<div className="w-56 shrink-0 space-y-4">
|
||||
|
||||
{/* Доп. места */}
|
||||
<div className="flex items-center justify-between px-3 py-2.5 rounded-xl bg-slate-50 dark:bg-slate-700/40 border border-slate-200 dark:border-slate-600">
|
||||
<div className="flex items-center gap-2">
|
||||
|
||||
@@ -12,9 +12,8 @@ interface ThemeContextValue {
|
||||
|
||||
const ThemeContext = createContext<ThemeContextValue | null>(null)
|
||||
|
||||
function getAutoTheme(): Theme {
|
||||
const h = new Date().getHours()
|
||||
return h >= 7 && h < 22 ? 'light' : 'dark'
|
||||
function getSystemTheme(): Theme {
|
||||
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
|
||||
}
|
||||
|
||||
export function ThemeProvider({ children }: { children: React.ReactNode }) {
|
||||
@@ -26,14 +25,16 @@ export function ThemeProvider({ children }: { children: React.ReactNode }) {
|
||||
const stored = localStorage.getItem('hotelsync-theme') as ThemeMode | null
|
||||
if (!stored || stored === 'light') return 'light'
|
||||
if (stored === 'dark') return 'dark'
|
||||
return getAutoTheme()
|
||||
return getSystemTheme()
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
if (mode === 'auto') {
|
||||
setTheme(getAutoTheme())
|
||||
const interval = setInterval(() => setTheme(getAutoTheme()), 60_000)
|
||||
return () => clearInterval(interval)
|
||||
setTheme(getSystemTheme())
|
||||
const mq = window.matchMedia('(prefers-color-scheme: dark)')
|
||||
const handler = (e: MediaQueryListEvent) => setTheme(e.matches ? 'dark' : 'light')
|
||||
mq.addEventListener('change', handler)
|
||||
return () => mq.removeEventListener('change', handler)
|
||||
} else {
|
||||
setTheme(mode)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user