+ availability
This commit is contained in:
97
resources/views/admin/hotels/_calendar.blade.php
Normal file
97
resources/views/admin/hotels/_calendar.blade.php
Normal file
@@ -0,0 +1,97 @@
|
||||
<div>
|
||||
@if($roomTypes->isEmpty())
|
||||
<p>Нет типов номеров. <a href="{{ route('admin.room-types.create') }}">Создать тип номера</a></p>
|
||||
@else
|
||||
@foreach($roomTypes as $type)
|
||||
<div style="margin-bottom: 25px; padding: 15px; border: 1px solid #eee; border-radius: 6px;">
|
||||
<h3>{{ $type->name }}</h3>
|
||||
|
||||
<!-- Форма добавления периода -->
|
||||
<form class="availability-form" data-room-type-id="{{ $type->id }}" style="margin-bottom: 15px;">
|
||||
@csrf
|
||||
<div style="display: flex; gap: 10px; margin-bottom: 10px;">
|
||||
<input type="date" name="start_date" required style="flex:1; padding:6px; border:1px solid #ccc; border-radius:4px;">
|
||||
<input type="date" name="end_date" required style="flex:1; padding:6px; border:1px solid #ccc; border-radius:4px;">
|
||||
</div>
|
||||
<div style="margin-bottom: 10px;">
|
||||
<label>
|
||||
<input type="checkbox" name="is_available" value="1" checked> Доступен
|
||||
</label>
|
||||
</div>
|
||||
<div style="margin-bottom: 10px;">
|
||||
<input type="number" name="price" step="0.01" placeholder="Цена" style="width:100%; padding:6px; border:1px solid #ccc; border-radius:4px;">
|
||||
</div>
|
||||
<button type="submit" class="btn" style="padding:6px 12px;">Сохранить</button>
|
||||
</form>
|
||||
|
||||
<!-- Список периодов -->
|
||||
@if($type->availabilities->isEmpty())
|
||||
<p>Нет периодов.</p>
|
||||
@else
|
||||
<table style="width:100%; font-size:0.9rem;">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>С</th>
|
||||
<th>По</th>
|
||||
<th>Статус</th>
|
||||
<th>Цена</th>
|
||||
<th>Действие</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($type->availabilities as $period)
|
||||
<tr>
|
||||
<td>{{ $period->start_date }}</td>
|
||||
<td>{{ $period->end_date }}</td>
|
||||
<td>
|
||||
@if($period->is_available)
|
||||
<span style="color:green;">Доступен</span>
|
||||
@else
|
||||
<span style="color:red;">Недоступен</span>
|
||||
@endif
|
||||
</td>
|
||||
<td>{{ $period->price ? number_format($period->price, 2) : '-' }}</td>
|
||||
<td>
|
||||
<form method="POST" action="/admin/availability/{{ $period->id }}" style="display:inline;">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
<button type="submit" class="btn btn-danger" style="padding:4px 8px; font-size:0.8rem;" onclick="return confirm('Удалить период?')">
|
||||
Удалить
|
||||
</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
@endif
|
||||
</div>
|
||||
@endforeach
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.querySelectorAll('.availability-form').forEach(form => {
|
||||
form.addEventListener('submit', async (e) => {
|
||||
e.preventDefault();
|
||||
const formData = new FormData(form);
|
||||
const roomTypeId = form.dataset.roomTypeId;
|
||||
|
||||
try {
|
||||
const response = await fetch(`/admin/room-types/${roomTypeId}/availability`, {
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
headers: { 'X-Requested-With': 'XMLHttpRequest' }
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
location.reload(); // Обновить модалку
|
||||
} else {
|
||||
alert('Ошибка сохранения');
|
||||
}
|
||||
} catch (error) {
|
||||
alert('Ошибка сети');
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -26,7 +26,7 @@
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn">Сохранить</button>
|
||||
<a href="{{ route('admin.hotels.index') }}" class="btn" style="background: #6c757d; text-decoration: none; margin-left: 10px;">Отмена</a>
|
||||
<a href="{{ route('admin.hotels.index') }}" class="btn" style="background: #6a1b9a; margin-left: 10px;">Отмена</a>
|
||||
</form>
|
||||
</div>
|
||||
@endsection
|
||||
@endsections
|
||||
@@ -27,7 +27,7 @@
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn">Сохранить</button>
|
||||
<a href="{{ route('admin.hotels.index') }}" class="btn" style="background: #6c757d; text-decoration: none; margin-left: 10px;">Отмена</a>
|
||||
<a href="{{ route('admin.hotels.index') }}" class="btn" style="background: #6a1b9a; margin-left: 10px;">Отмена</a>
|
||||
</form>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -4,7 +4,7 @@
|
||||
<div>
|
||||
<h1>Отели</h1>
|
||||
|
||||
<a href="{{ route('admin.hotels.create') }}" class="btn" style="display: inline-block; margin-bottom: 20px;">Добавить отель</a>
|
||||
<a href="{{ route('admin.hotels.create') }}" class="btn">Добавить отель</a>
|
||||
|
||||
@if($hotels->isEmpty())
|
||||
<p>Нет отелей.</p>
|
||||
@@ -25,14 +25,20 @@
|
||||
<td>{{ $hotel->address ?? '-' }}</td>
|
||||
<td>{{ $hotel->phone ?? '-' }}</td>
|
||||
<td>
|
||||
<a href="{{ route('admin.hotels.edit', $hotel) }}" class="btn" style="background: #6c757d; margin-right: 6px;">Редактировать</a>
|
||||
<a href="{{ route('admin.hotels.edit', $hotel) }}" class="btn" style="margin-right: 5px;">
|
||||
Редактировать
|
||||
</a>
|
||||
<form action="{{ route('admin.hotels.destroy', $hotel) }}" method="POST" style="display: inline;">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
<button type="submit" class="btn" style="background: #aaa;" onclick="return confirm('Удалить отель?')">
|
||||
<button type="submit" class="btn btn-danger" style="margin-right: 5px;" onclick="return confirm('Удалить отель?')">
|
||||
Удалить
|
||||
</button>
|
||||
</form>
|
||||
<!-- Кнопка шахматки -->
|
||||
<button type="button" class="btn btn-secondary open-calendar-modal" data-hotel-id="{{ $hotel->id }}">
|
||||
Календарь
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
@@ -40,4 +46,43 @@
|
||||
</table>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<!-- Модальное окно для шахматки -->
|
||||
<div id="calendarModal" style="display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.5);z-index:1000;">
|
||||
<div style="background:white;margin:50px auto;padding:25px;border-radius:8px;max-width:800px;box-shadow:0 4px 20px rgba(0,0,0,0.3);">
|
||||
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:20px;">
|
||||
<h2>Доступные даты: <span id="modalHotelName"></span></h2>
|
||||
<button id="closeCalendarModal" style="background:none;border:none;font-size:1.5rem;cursor:pointer;">×</button>
|
||||
</div>
|
||||
<div id="calendarModalContent">Загрузка...</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
const modal = document.getElementById('calendarModal');
|
||||
const closeModalBtn = document.getElementById('closeCalendarModal');
|
||||
|
||||
document.querySelectorAll('.open-calendar-modal').forEach(button => {
|
||||
button.addEventListener('click', async function () {
|
||||
const hotelId = this.dataset.hotelId;
|
||||
const hotelName = this.closest('tr').querySelector('td:first-child').textContent;
|
||||
|
||||
try {
|
||||
const response = await fetch(`/admin/hotels/${hotelId}/calendar`, {
|
||||
headers: { 'X-Requested-With': 'XMLHttpRequest' }
|
||||
});
|
||||
document.getElementById('modalHotelName').textContent = hotelName;
|
||||
document.getElementById('calendarModalContent').innerHTML = await response.text();
|
||||
modal.style.display = 'block';
|
||||
} catch (e) {
|
||||
alert('Ошибка загрузки шахматки');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
closeModalBtn.onclick = () => modal.style.display = 'none';
|
||||
window.onclick = (e) => { if (e.target === modal) modal.style.display = 'none'; };
|
||||
});
|
||||
</script>
|
||||
@endsection
|
||||
@@ -17,7 +17,7 @@
|
||||
padding: 20px;
|
||||
}
|
||||
header {
|
||||
background-color: #4a4a4a;
|
||||
background-color: #4a148c;
|
||||
color: white;
|
||||
padding: 15px 20px;
|
||||
display: flex;
|
||||
@@ -26,10 +26,6 @@
|
||||
margin-bottom: 25px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
header h1 {
|
||||
margin: 0;
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
nav a {
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
@@ -39,7 +35,7 @@
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
nav a:hover {
|
||||
background-color: #5a5a5a;
|
||||
background-color: #6a1b9a;
|
||||
}
|
||||
main {
|
||||
background: white;
|
||||
@@ -47,13 +43,9 @@
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
|
||||
}
|
||||
h1, h2, h3 {
|
||||
color: #2d2d2d;
|
||||
margin-top: 0;
|
||||
}
|
||||
.btn {
|
||||
display: inline-block;
|
||||
background-color: #6c757d;
|
||||
background-color: #4a148c;
|
||||
color: white;
|
||||
padding: 8px 16px;
|
||||
text-decoration: none;
|
||||
@@ -63,37 +55,14 @@
|
||||
font-size: 0.95rem;
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
.btn:hover {
|
||||
background-color: #5a6268;
|
||||
}
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin: 20px 0;
|
||||
}
|
||||
th, td {
|
||||
padding: 12px 15px;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid #eaeaea;
|
||||
}
|
||||
th {
|
||||
background-color: #f1f1f1;
|
||||
font-weight: 600;
|
||||
color: #444;
|
||||
}
|
||||
tr:hover {
|
||||
background-color: #fafafa;
|
||||
}
|
||||
.alert {
|
||||
padding: 12px;
|
||||
margin: 16px 0;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.alert-success {
|
||||
background-color: #e0f0e0;
|
||||
color: #2d5d2d;
|
||||
border-left: 4px solid #4caf50;
|
||||
}
|
||||
.btn:hover { background-color: #6a1b9a; }
|
||||
.btn-secondary { background-color: #7b1fa2; }
|
||||
.btn-secondary:hover { background-color: #9c27b0; }
|
||||
.btn-danger { background-color: #000000; }
|
||||
.btn-danger:hover { background-color: #212121; }
|
||||
table { width: 100%; border-collapse: collapse; margin: 20px 0; }
|
||||
th, td { padding: 12px 15px; text-align: left; border-bottom: 1px solid #eaeaea; }
|
||||
th { background-color: #f1f1f1; font-weight: 600; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -102,17 +71,17 @@
|
||||
<nav>
|
||||
<a href="{{ route('admin.hotels.index') }}">Отели</a>
|
||||
<form action="{{ route('admin.logout') }}" method="POST" style="display: inline;">
|
||||
@csrf
|
||||
<button type="submit" style="background: none; border: none; color: white; cursor: pointer; padding: 6px 12px; border-radius: 4px;">
|
||||
Выйти
|
||||
</button>
|
||||
</form>
|
||||
@csrf
|
||||
<button type="submit" style="background: none; border: none; color: white; cursor: pointer;">Выйти</button>
|
||||
</form>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
@if(session('success'))
|
||||
<div class="alert alert-success">{{ session('success') }}</div>
|
||||
<div style="padding:12px;background:#e0f0e0;color:#2d5d2d;border-left:4px solid #4caf50;margin:16px 0;border-radius:4px;">
|
||||
{{ session('success') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@yield('content')
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<h2>Вход в админку</h2>
|
||||
|
||||
@if ($errors->any())
|
||||
<div class="alert alert-error" style="background: #ffeaea; color: #c0392b; padding: 12px; border-radius: 4px; border-left: 4px solid #e74c3c; margin-bottom: 20px;">
|
||||
<div style="background: #ffeaea; color: #c0392b; padding: 12px; border-radius: 4px; margin-bottom: 20px;">
|
||||
Неверные данные.
|
||||
</div>
|
||||
@endif
|
||||
@@ -13,16 +13,15 @@
|
||||
<form method="POST" action="{{ route('admin.login') }}">
|
||||
@csrf
|
||||
<div style="margin-bottom: 15px;">
|
||||
<label for="email" style="display: block; margin-bottom: 6px; font-weight: 500;">Email</label>
|
||||
<label for="email" style="display: block; margin-bottom: 6px;">Email</label>
|
||||
<input type="email" name="email" id="email" required
|
||||
style="width: 100%; padding: 10px; border: 1px solid #ccc; border-radius: 4px; box-sizing: border-box;"
|
||||
value="{{ old('email') }}">
|
||||
style="width: 100%; padding: 10px; border: 1px solid #ccc; border-radius: 4px;" value="{{ old('email') }}">
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 20px;">
|
||||
<label for="password" style="display: block; margin-bottom: 6px; font-weight: 500;">Пароль</label>
|
||||
<label for="password" style="display: block; margin-bottom: 6px;">Пароль</label>
|
||||
<input type="password" name="password" id="password" required
|
||||
style="width: 100%; padding: 10px; border: 1px solid #ccc; border-radius: 4px; box-sizing: border-box;">
|
||||
style="width: 100%; padding: 10px; border: 1px solid #ccc; border-radius: 4px;">
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn" style="width: 100%;">Войти</button>
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
@extends('admin.layout')
|
||||
|
||||
@section('content')
|
||||
<div style="text-align: center; padding: 40px;">
|
||||
<h2>Вы вышли из системы</h2>
|
||||
<p>До скорой встречи!</p>
|
||||
<a href="{{ route('admin.login.form') }}" class="btn">Войти снова</a>
|
||||
</div>
|
||||
@endsection
|
||||
Reference in New Issue
Block a user