Fix mobile responsiveness across all pages
- PosPage: rooms list becomes horizontal scroll row on mobile instead of w-56 sidebar - AvailabilityPage: edit panel stacks below grid on mobile (was fixed w-80 side panel) - UsersPage roles tab: sidebar stacks above permissions on mobile - All page containers: p-6 → p-4 md:p-6 (TariffsPage, DiscountsPage, MaintenancePage, ReportsPage, DynamicPricingPage, GuestsPage, LoyaltyPage) - Stats grids: lg:grid-cols-4 → md:grid-cols-4 (GuestsPage, TariffsPage, DiscountsPage, MaintenancePage, ReportsPage, LoyaltyPage) - Modal form grids: grid-cols-3 → grid-cols-1 sm:grid-cols-3, grid-cols-5 → grid-cols-3 sm:grid-cols-5, grid-cols-4 → grid-cols-2 sm:grid-cols-4 - PosPage modals: fixed w-80/w-96 → responsive w-[calc(100vw-2rem)] sm:w-80/96 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -265,7 +265,7 @@ function EditPanel({
|
|||||||
}, [startDate, endDate])
|
}, [startDate, endDate])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-80 shrink-0 border-l border-slate-200 dark:border-slate-700 bg-white dark:bg-slate-800 flex flex-col overflow-y-auto">
|
<div className="w-full sm:w-80 shrink-0 border-t sm:border-t-0 sm:border-l border-slate-200 dark:border-slate-700 bg-white dark:bg-slate-800 flex flex-col overflow-y-auto max-h-72 sm:max-h-none">
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="flex items-center justify-between px-4 py-3 border-b border-slate-200 dark:border-slate-700">
|
<div className="flex items-center justify-between px-4 py-3 border-b border-slate-200 dark:border-slate-700">
|
||||||
<div>
|
<div>
|
||||||
@@ -922,7 +922,7 @@ export function AvailabilityPage() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* ── Content ── */}
|
{/* ── Content ── */}
|
||||||
<div className="flex-1 overflow-hidden flex">
|
<div className="flex-1 overflow-hidden flex flex-col sm:flex-row">
|
||||||
|
|
||||||
{/* Grid tab */}
|
{/* Grid tab */}
|
||||||
{tab === 'grid' && (
|
{tab === 'grid' && (
|
||||||
|
|||||||
@@ -140,8 +140,8 @@ function DiscountModal({
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<div className="grid grid-cols-3 gap-3">
|
<div className="grid grid-cols-1 sm:grid-cols-3 gap-3">
|
||||||
<div className="col-span-2">
|
<div className="sm:col-span-2">
|
||||||
<label className="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1.5">Название *</label>
|
<label className="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1.5">Название *</label>
|
||||||
<input type="text" className="input" placeholder="Корпоративная скидка"
|
<input type="text" className="input" placeholder="Корпоративная скидка"
|
||||||
value={form.name} onChange={e => set('name', e.target.value)} />
|
value={form.name} onChange={e => set('name', e.target.value)} />
|
||||||
@@ -285,7 +285,7 @@ export function DiscountsPage() {
|
|||||||
setDiscounts(prev => prev.map(d => d.id === id ? { ...d, isActive: !d.isActive } : d))
|
setDiscounts(prev => prev.map(d => d.id === id ? { ...d, isActive: !d.isActive } : d))
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="p-6 space-y-6">
|
<div className="p-4 md:p-6 space-y-6">
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div>
|
<div>
|
||||||
@@ -301,7 +301,7 @@ export function DiscountsPage() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Stats */}
|
{/* Stats */}
|
||||||
<div className="grid grid-cols-2 lg:grid-cols-4 gap-3">
|
<div className="grid grid-cols-2 md:grid-cols-4 gap-3">
|
||||||
{[
|
{[
|
||||||
{ label: 'Всего скидок', value: discounts.length },
|
{ label: 'Всего скидок', value: discounts.length },
|
||||||
{ label: 'Активных', value: discounts.filter(d => d.isActive).length },
|
{ label: 'Активных', value: discounts.filter(d => d.isActive).length },
|
||||||
|
|||||||
@@ -772,7 +772,7 @@ export function DynamicPricingPage() {
|
|||||||
setRules(prev => prev.map(r => r.id === id ? { ...r, isActive: !r.isActive } : r))
|
setRules(prev => prev.map(r => r.id === id ? { ...r, isActive: !r.isActive } : r))
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="p-6 space-y-6">
|
<div className="p-4 md:p-6 space-y-6">
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -287,7 +287,7 @@ function GuestModal({ guest, onClose }: { guest: Guest; onClose: () => void }) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Body */}
|
{/* Body */}
|
||||||
<div className="flex-1 overflow-y-auto p-6">
|
<div className="flex-1 overflow-y-auto p-4 sm:p-6">
|
||||||
{tab === 'overview' && (
|
{tab === 'overview' && (
|
||||||
<div className="space-y-5">
|
<div className="space-y-5">
|
||||||
{/* Tags */}
|
{/* Tags */}
|
||||||
@@ -556,7 +556,7 @@ export function GuestsPage() {
|
|||||||
const avgRating = (MOCK_GUESTS.reduce((s, g) => s + g.rating, 0) / MOCK_GUESTS.length).toFixed(1)
|
const avgRating = (MOCK_GUESTS.reduce((s, g) => s + g.rating, 0) / MOCK_GUESTS.length).toFixed(1)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="p-6 space-y-6">
|
<div className="p-4 md:p-6 space-y-6">
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div>
|
<div>
|
||||||
<h1 className="text-2xl font-bold text-slate-900 dark:text-slate-100">Гости</h1>
|
<h1 className="text-2xl font-bold text-slate-900 dark:text-slate-100">Гости</h1>
|
||||||
@@ -588,7 +588,7 @@ export function GuestsPage() {
|
|||||||
{pageTab === 'list' && <>
|
{pageTab === 'list' && <>
|
||||||
|
|
||||||
{/* Stats */}
|
{/* Stats */}
|
||||||
<div className="grid grid-cols-2 lg:grid-cols-4 gap-3">
|
<div className="grid grid-cols-2 md:grid-cols-4 gap-3">
|
||||||
{[
|
{[
|
||||||
{ icon: Users, label: 'Всего гостей', value: MOCK_GUESTS.length, color: 'text-brand-600 dark:text-brand-400', bg: 'bg-brand-50 dark:bg-brand-900/20' },
|
{ icon: Users, label: 'Всего гостей', value: MOCK_GUESTS.length, color: 'text-brand-600 dark:text-brand-400', bg: 'bg-brand-50 dark:bg-brand-900/20' },
|
||||||
{ icon: Award, label: 'VIP гостей', value: vipCount, color: 'text-amber-600 dark:text-amber-400', bg: 'bg-amber-50 dark:bg-amber-900/20' },
|
{ icon: Award, label: 'VIP гостей', value: vipCount, color: 'text-amber-600 dark:text-amber-400', bg: 'bg-amber-50 dark:bg-amber-900/20' },
|
||||||
|
|||||||
@@ -815,7 +815,7 @@ export function LoyaltyPage() {
|
|||||||
const totalPoints = MOCK_GUESTS.reduce((s, g) => s + g.points, 0)
|
const totalPoints = MOCK_GUESTS.reduce((s, g) => s + g.points, 0)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="p-6 space-y-5">
|
<div className="p-4 md:p-6 space-y-5">
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div>
|
<div>
|
||||||
@@ -837,7 +837,7 @@ export function LoyaltyPage() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Stats */}
|
{/* Stats */}
|
||||||
<div className="grid grid-cols-2 lg:grid-cols-4 gap-3">
|
<div className="grid grid-cols-2 md:grid-cols-4 gap-3">
|
||||||
{[
|
{[
|
||||||
{ label: 'Участников программы', value: activeGuests, icon: User, color: 'text-brand-600 dark:text-brand-400', bg: 'bg-brand-50 dark:bg-brand-900/20' },
|
{ label: 'Участников программы', value: activeGuests, icon: User, color: 'text-brand-600 dark:text-brand-400', bg: 'bg-brand-50 dark:bg-brand-900/20' },
|
||||||
{ label: 'Всего баллов в обороте', value: totalPoints.toLocaleString('ru-RU'), icon: TrendingUp, color: 'text-amber-600 dark:text-amber-400', bg: 'bg-amber-50 dark:bg-amber-900/20' },
|
{ label: 'Всего баллов в обороте', value: totalPoints.toLocaleString('ru-RU'), icon: TrendingUp, color: 'text-amber-600 dark:text-amber-400', bg: 'bg-amber-50 dark:bg-amber-900/20' },
|
||||||
@@ -885,7 +885,7 @@ export function LoyaltyPage() {
|
|||||||
{editSettings ? <><Save size={13} /> Сохранить</> : <><Edit2 size={13} /> Изменить</>}
|
{editSettings ? <><Save size={13} /> Сохранить</> : <><Edit2 size={13} /> Изменить</>}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-3 gap-4">
|
<div className="grid grid-cols-1 sm:grid-cols-3 gap-4">
|
||||||
{[
|
{[
|
||||||
{ label: 'Начисление', desc: `${settings.pointsPerRuble} балл за 1 ₽`, field: 'pointsPerRuble' as const, unit: 'балл/₽' },
|
{ label: 'Начисление', desc: `${settings.pointsPerRuble} балл за 1 ₽`, field: 'pointsPerRuble' as const, unit: 'балл/₽' },
|
||||||
{ label: 'Ценность', desc: `1 балл = ${settings.pointValue} ₽`, field: 'pointValue' as const, unit: '₽' },
|
{ label: 'Ценность', desc: `1 балл = ${settings.pointValue} ₽`, field: 'pointValue' as const, unit: '₽' },
|
||||||
|
|||||||
@@ -231,7 +231,7 @@ function MaintenanceModal({
|
|||||||
{/* Type selector */}
|
{/* Type selector */}
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">Тип</label>
|
<label className="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">Тип</label>
|
||||||
<div className="grid grid-cols-3 gap-2">
|
<div className="grid grid-cols-3 sm:grid-cols-3 gap-2">
|
||||||
{([
|
{([
|
||||||
{ id: 'room' as const, label: 'Номер', icon: BedDouble },
|
{ id: 'room' as const, label: 'Номер', icon: BedDouble },
|
||||||
{ id: 'service' as const, label: 'Услуга', icon: Wrench },
|
{ id: 'service' as const, label: 'Услуга', icon: Wrench },
|
||||||
@@ -362,7 +362,7 @@ export function MaintenancePage() {
|
|||||||
const active = records.filter(r => r.status !== 'done' && r.status !== 'cancelled')
|
const active = records.filter(r => r.status !== 'done' && r.status !== 'cancelled')
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="p-6 space-y-6">
|
<div className="p-4 md:p-6 space-y-6">
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div>
|
<div>
|
||||||
@@ -378,7 +378,7 @@ export function MaintenancePage() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Stats */}
|
{/* Stats */}
|
||||||
<div className="grid grid-cols-2 lg:grid-cols-4 gap-3">
|
<div className="grid grid-cols-2 md:grid-cols-4 gap-3">
|
||||||
{[
|
{[
|
||||||
{ label: 'Всего записей', value: records.length, cls: '' },
|
{ label: 'Всего записей', value: records.length, cls: '' },
|
||||||
{ label: 'Активных', value: active.length, cls: 'text-amber-600 dark:text-amber-400' },
|
{ label: 'Активных', value: active.length, cls: 'text-amber-600 dark:text-amber-400' },
|
||||||
|
|||||||
@@ -270,14 +270,41 @@ export function PosPage() {
|
|||||||
<>
|
<>
|
||||||
{/* ══════════════════════ TAB: main ══════════════════════ */}
|
{/* ══════════════════════ TAB: main ══════════════════════ */}
|
||||||
{activeTab === 'main' && (
|
{activeTab === 'main' && (
|
||||||
<div className="flex flex-1 overflow-hidden">
|
<div className="flex flex-col sm:flex-row flex-1 overflow-hidden">
|
||||||
|
|
||||||
{/* ── Left sidebar: Заезды (w-56) ── */}
|
{/* ── Заезды: horizontal scroll on mobile, sidebar on desktop ── */}
|
||||||
<div className="w-56 flex flex-col border-r border-slate-200 dark:border-slate-700 bg-slate-50 dark:bg-slate-800/50 shrink-0 overflow-hidden">
|
<div className="sm:w-56 flex-shrink-0 border-b sm:border-b-0 sm:border-r border-slate-200 dark:border-slate-700 bg-slate-50 dark:bg-slate-800/50">
|
||||||
<div className="px-3 py-2 border-b border-slate-200 dark:border-slate-700">
|
<div className="px-3 py-2 border-b border-slate-200 dark:border-slate-700 hidden sm:block">
|
||||||
<p className="text-[11px] font-semibold text-slate-500 dark:text-slate-400 uppercase tracking-wide">Заезды</p>
|
<p className="text-[11px] font-semibold text-slate-500 dark:text-slate-400 uppercase tracking-wide">Заезды</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-1 overflow-y-auto p-2 space-y-1">
|
{/* Mobile: horizontal scroll row */}
|
||||||
|
<div className="flex sm:hidden gap-2 p-2 overflow-x-auto">
|
||||||
|
{MOCK_BALANCES.map(rb => {
|
||||||
|
const debt = Math.max(0, rb.totalAmount - rb.paidAmount)
|
||||||
|
const paid = debt === 0
|
||||||
|
const sel = selectedRoom?.roomId === rb.roomId
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
key={rb.roomId}
|
||||||
|
onClick={() => setSelectedRoom(rb)}
|
||||||
|
className={cn(
|
||||||
|
'shrink-0 rounded-lg px-3 py-1.5 border transition-all flex items-center gap-1.5',
|
||||||
|
sel
|
||||||
|
? 'border-brand-400 bg-brand-50 dark:bg-brand-900/20 dark:border-brand-600'
|
||||||
|
: 'border-slate-200 dark:border-slate-600 bg-white dark:bg-slate-800',
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<span className="text-xs font-bold text-slate-900 dark:text-slate-100">№{rb.roomNumber}</span>
|
||||||
|
{paid
|
||||||
|
? <span className="text-[9px] font-semibold px-1 py-0.5 rounded-full bg-emerald-100 text-emerald-700 dark:bg-emerald-900/30 dark:text-emerald-300">✓</span>
|
||||||
|
: <span className="text-[9px] font-semibold px-1 py-0.5 rounded-full bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-300 whitespace-nowrap">{formatCurrency(debt)}</span>
|
||||||
|
}
|
||||||
|
</button>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
{/* Desktop: vertical list */}
|
||||||
|
<div className="hidden sm:block flex-1 overflow-y-auto p-2 space-y-1">
|
||||||
{MOCK_BALANCES.map(rb => {
|
{MOCK_BALANCES.map(rb => {
|
||||||
const debt = Math.max(0, rb.totalAmount - rb.paidAmount)
|
const debt = Math.max(0, rb.totalAmount - rb.paidAmount)
|
||||||
const paid = debt === 0
|
const paid = debt === 0
|
||||||
@@ -313,7 +340,7 @@ export function PosPage() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* ── Center: payment form ── */}
|
{/* ── Center: payment form ── */}
|
||||||
<div className="flex-1 flex flex-col overflow-y-auto p-5 gap-5">
|
<div className="flex-1 flex flex-col overflow-y-auto p-4 sm:p-5 gap-5">
|
||||||
{selectedRoom ? (
|
{selectedRoom ? (
|
||||||
<>
|
<>
|
||||||
{/* Guest info */}
|
{/* Guest info */}
|
||||||
@@ -781,7 +808,7 @@ export function PosPage() {
|
|||||||
{/* ── Receipt success overlay ── */}
|
{/* ── Receipt success overlay ── */}
|
||||||
{lastReceipt && (
|
{lastReceipt && (
|
||||||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/50">
|
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/50">
|
||||||
<div className="bg-white dark:bg-slate-800 rounded-2xl shadow-2xl p-8 w-80 text-center space-y-4">
|
<div className="bg-white dark:bg-slate-800 rounded-2xl shadow-2xl p-6 sm:p-8 w-[calc(100vw-2rem)] sm:w-80 text-center space-y-4">
|
||||||
<CheckCircle2 size={56} className="text-emerald-500 mx-auto" />
|
<CheckCircle2 size={56} className="text-emerald-500 mx-auto" />
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xl font-bold text-slate-900 dark:text-slate-100">Оплата принята</p>
|
<p className="text-xl font-bold text-slate-900 dark:text-slate-100">Оплата принята</p>
|
||||||
@@ -815,7 +842,7 @@ export function PosPage() {
|
|||||||
{/* ── Close shift confirmation modal ── */}
|
{/* ── Close shift confirmation modal ── */}
|
||||||
{closeConfirm && (
|
{closeConfirm && (
|
||||||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/50">
|
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/50">
|
||||||
<div className="bg-white dark:bg-slate-800 rounded-2xl shadow-2xl p-6 w-96 space-y-4">
|
<div className="bg-white dark:bg-slate-800 rounded-2xl shadow-2xl p-6 w-[calc(100vw-2rem)] sm:w-96 space-y-4">
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<div className="w-10 h-10 rounded-full bg-red-100 dark:bg-red-900/30 flex items-center justify-center">
|
<div className="w-10 h-10 rounded-full bg-red-100 dark:bg-red-900/30 flex items-center justify-center">
|
||||||
<Printer size={18} className="text-red-600" />
|
<Printer size={18} className="text-red-600" />
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ const maxOcc = Math.max(...OCC)
|
|||||||
|
|
||||||
export function ReportsPage() {
|
export function ReportsPage() {
|
||||||
return (
|
return (
|
||||||
<div className="p-6 max-w-5xl mx-auto space-y-6">
|
<div className="p-4 md:p-6 max-w-5xl mx-auto space-y-6">
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<div className="w-10 h-10 rounded-xl bg-cyan-600 flex items-center justify-center shrink-0">
|
<div className="w-10 h-10 rounded-xl bg-cyan-600 flex items-center justify-center shrink-0">
|
||||||
<BarChart3 size={20} className="text-white" />
|
<BarChart3 size={20} className="text-white" />
|
||||||
@@ -33,7 +33,7 @@ export function ReportsPage() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* KPI cards */}
|
{/* KPI cards */}
|
||||||
<div className="grid grid-cols-2 lg:grid-cols-4 gap-3">
|
<div className="grid grid-cols-2 md:grid-cols-4 gap-3">
|
||||||
{KPI.map(k => (
|
{KPI.map(k => (
|
||||||
<div key={k.label} className="bg-white dark:bg-slate-800 rounded-xl border border-slate-200 dark:border-slate-700 p-4">
|
<div key={k.label} className="bg-white dark:bg-slate-800 rounded-xl border border-slate-200 dark:border-slate-700 p-4">
|
||||||
<p className="text-xs text-slate-500 dark:text-slate-400 mb-2">{k.label}</p>
|
<p className="text-xs text-slate-500 dark:text-slate-400 mb-2">{k.label}</p>
|
||||||
|
|||||||
@@ -200,8 +200,8 @@ function TariffModal({
|
|||||||
>
|
>
|
||||||
<div className="space-y-5">
|
<div className="space-y-5">
|
||||||
{/* Name + Code */}
|
{/* Name + Code */}
|
||||||
<div className="grid grid-cols-3 gap-3">
|
<div className="grid grid-cols-1 sm:grid-cols-3 gap-3">
|
||||||
<div className="col-span-2">
|
<div className="sm:col-span-2">
|
||||||
<label className="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1.5">
|
<label className="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1.5">
|
||||||
Название тарифа *
|
Название тарифа *
|
||||||
</label>
|
</label>
|
||||||
@@ -223,7 +223,7 @@ function TariffModal({
|
|||||||
<label className="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">
|
<label className="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">
|
||||||
Тип питания
|
Тип питания
|
||||||
</label>
|
</label>
|
||||||
<div className="grid grid-cols-5 gap-2">
|
<div className="grid grid-cols-3 sm:grid-cols-5 gap-2">
|
||||||
{mealPlans.map(mp => (
|
{mealPlans.map(mp => (
|
||||||
<button
|
<button
|
||||||
key={mp.id}
|
key={mp.id}
|
||||||
@@ -250,7 +250,7 @@ function TariffModal({
|
|||||||
<label className="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">
|
<label className="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">
|
||||||
Что включено
|
Что включено
|
||||||
</label>
|
</label>
|
||||||
<div className="grid grid-cols-4 gap-2">
|
<div className="grid grid-cols-2 sm:grid-cols-4 gap-2">
|
||||||
{allInclusions.map(inc => {
|
{allInclusions.map(inc => {
|
||||||
const active = form.inclusions.includes(inc.id)
|
const active = form.inclusions.includes(inc.id)
|
||||||
return (
|
return (
|
||||||
@@ -278,7 +278,7 @@ function TariffModal({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Price modifier + min nights + cancellation */}
|
{/* Price modifier + min nights + cancellation */}
|
||||||
<div className="grid grid-cols-3 gap-4">
|
<div className="grid grid-cols-1 sm:grid-cols-3 gap-4">
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1.5">
|
<label className="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1.5">
|
||||||
Надбавка / скидка к базовой цене
|
Надбавка / скидка к базовой цене
|
||||||
@@ -413,7 +413,7 @@ export function TariffsPage() {
|
|||||||
const inactiveTariffs = tariffs.filter(t => !t.isActive)
|
const inactiveTariffs = tariffs.filter(t => !t.isActive)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="p-6 space-y-6">
|
<div className="p-4 md:p-6 space-y-6">
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div>
|
<div>
|
||||||
@@ -429,7 +429,7 @@ export function TariffsPage() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Stats */}
|
{/* Stats */}
|
||||||
<div className="grid grid-cols-2 lg:grid-cols-4 gap-3">
|
<div className="grid grid-cols-2 md:grid-cols-4 gap-3">
|
||||||
{[
|
{[
|
||||||
{ label: 'Всего тарифов', value: tariffs.length, color: 'text-slate-900 dark:text-slate-100' },
|
{ label: 'Всего тарифов', value: tariffs.length, color: 'text-slate-900 dark:text-slate-100' },
|
||||||
{ label: 'Активных', value: activeTariffs.length, color: 'text-emerald-600 dark:text-emerald-400' },
|
{ label: 'Активных', value: activeTariffs.length, color: 'text-emerald-600 dark:text-emerald-400' },
|
||||||
|
|||||||
@@ -473,9 +473,9 @@ function RolesTab() {
|
|||||||
const totalCount = ALL_MODULE_KEYS.length
|
const totalCount = ALL_MODULE_KEYS.length
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex gap-5 items-start">
|
<div className="flex flex-col sm:flex-row gap-5 items-start">
|
||||||
{/* Role list */}
|
{/* Role list */}
|
||||||
<div className="w-52 shrink-0">
|
<div className="w-full sm:w-52 shrink-0">
|
||||||
<div className="card overflow-hidden">
|
<div className="card overflow-hidden">
|
||||||
<div className="p-3 border-b border-slate-100 dark:border-slate-700">
|
<div className="p-3 border-b border-slate-100 dark:border-slate-700">
|
||||||
<p className="text-xs font-semibold text-slate-500 dark:text-slate-400 uppercase tracking-wide">Роли</p>
|
<p className="text-xs font-semibold text-slate-500 dark:text-slate-400 uppercase tracking-wide">Роли</p>
|
||||||
|
|||||||
Reference in New Issue
Block a user