feat: Оптимизация навигации AdminJS в логические группы
- Объединены ресурсы в 5 логических групп: Контент сайта, Бронирования, Отзывы и рейтинги, Персонал и гиды, Администрирование - Удалены дублирующие настройки navigation для чистой группировки - Добавлены CSS стили для визуального отображения иерархии с отступами - Добавлены эмодзи-иконки для каждого типа ресурсов через CSS - Улучшена навигация с правильной вложенностью элементов
This commit is contained in:
@@ -32,7 +32,101 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
});
|
||||
|
||||
// ==========================================
|
||||
// Поиск по сайту
|
||||
// Инициализация компонентов бронирования
|
||||
// ==========================================
|
||||
|
||||
// Компонент для проверки доступности на главной странице
|
||||
const availabilityContainer = document.getElementById('availability-checker-container');
|
||||
const guideSelectorContainer = document.getElementById('guide-selector-container');
|
||||
|
||||
if (availabilityContainer) {
|
||||
const availabilityChecker = new AvailabilityChecker({
|
||||
container: availabilityContainer,
|
||||
mode: 'detailed',
|
||||
showSuggestions: true,
|
||||
onAvailabilityCheck: function(result) {
|
||||
if (result.availableGuides && result.availableGuides.length > 0) {
|
||||
// Показать селектор гидов если есть доступные
|
||||
if (guideSelectorContainer) {
|
||||
guideSelectorContainer.style.display = 'block';
|
||||
|
||||
const guideSelector = new GuideSelector({
|
||||
container: guideSelectorContainer,
|
||||
mode: 'booking',
|
||||
showAvailability: true,
|
||||
selectedDate: result.date,
|
||||
onGuideSelect: function(guide) {
|
||||
// Перейти к бронированию с выбранным гидом
|
||||
window.location.href = `/routes?guide=${guide.id}&date=${result.date}`;
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (guideSelectorContainer) {
|
||||
guideSelectorContainer.style.display = 'none';
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Календарь гидов на странице гидов
|
||||
const guidesCalendarContainer = document.getElementById('guides-calendar-container');
|
||||
if (guidesCalendarContainer) {
|
||||
const guidesCalendar = new GuideCalendarWidget({
|
||||
container: guidesCalendarContainer,
|
||||
mode: 'readonly',
|
||||
showControls: false,
|
||||
showGuideInfo: true
|
||||
});
|
||||
}
|
||||
|
||||
// Компоненты бронирования на странице маршрута
|
||||
const bookingAvailabilityContainer = document.getElementById('booking-availability-checker');
|
||||
const bookingGuideSelectorContainer = document.getElementById('booking-guide-selector');
|
||||
|
||||
if (bookingAvailabilityContainer) {
|
||||
const bookingAvailabilityChecker = new AvailabilityChecker({
|
||||
container: bookingAvailabilityContainer,
|
||||
mode: 'inline',
|
||||
showSuggestions: false,
|
||||
onAvailabilityCheck: function(result) {
|
||||
if (result.availableGuides && result.availableGuides.length > 0) {
|
||||
if (bookingGuideSelectorContainer) {
|
||||
bookingGuideSelectorContainer.style.display = 'block';
|
||||
|
||||
const bookingGuideSelector = new GuideSelector({
|
||||
container: bookingGuideSelectorContainer,
|
||||
mode: 'booking',
|
||||
showAvailability: false,
|
||||
availableGuides: result.availableGuides,
|
||||
onGuideSelect: function(guide) {
|
||||
// Заполнить скрытое поле с ID гида
|
||||
const selectedGuideIdInput = document.getElementById('selectedGuideId');
|
||||
const preferredDateInput = document.getElementById('preferred_date');
|
||||
const submitBtn = document.getElementById('submitBookingBtn');
|
||||
|
||||
if (selectedGuideIdInput) {
|
||||
selectedGuideIdInput.value = guide.id;
|
||||
}
|
||||
|
||||
if (preferredDateInput) {
|
||||
preferredDateInput.value = result.date;
|
||||
}
|
||||
|
||||
if (submitBtn) {
|
||||
submitBtn.disabled = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// Поиск по сайту (обновленная версия)
|
||||
// ==========================================
|
||||
const searchInput = document.getElementById('search-input');
|
||||
const searchResults = document.getElementById('search-results');
|
||||
@@ -378,6 +472,101 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// Вспомогательные функции для компонентов
|
||||
// ==========================================
|
||||
|
||||
// Очистка результатов поиска
|
||||
function clearSearchResults() {
|
||||
const resultsContainer = document.getElementById('searchResults');
|
||||
if (resultsContainer) {
|
||||
resultsContainer.style.display = 'none';
|
||||
}
|
||||
|
||||
const guideSelectorContainer = document.getElementById('guide-selector-container');
|
||||
if (guideSelectorContainer) {
|
||||
guideSelectorContainer.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
// Функция для быстрого бронирования (вызывается из компонентов)
|
||||
function quickBookTour(routeId, guideId, date, peopleCount = 1) {
|
||||
// Создаем модальное окно для быстрого бронирования
|
||||
const modal = document.createElement('div');
|
||||
modal.className = 'modal fade';
|
||||
modal.innerHTML = `
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Бронирование тура</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="quickBookingForm" action="/bookings" method="POST">
|
||||
<input type="hidden" name="route_id" value="${routeId}">
|
||||
<input type="hidden" name="guide_id" value="${guideId}">
|
||||
<input type="hidden" name="preferred_date" value="${date}">
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Ваше имя *</label>
|
||||
<input type="text" class="form-control" name="customer_name" required>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Количество человек</label>
|
||||
<input type="number" class="form-control" name="people_count" value="${peopleCount}" min="1" max="20" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Email *</label>
|
||||
<input type="email" class="form-control" name="customer_email" required>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Телефон *</label>
|
||||
<input type="tel" class="form-control" name="customer_phone" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Особые пожелания</label>
|
||||
<textarea class="form-control" name="special_requirements" rows="3"></textarea>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Отмена</button>
|
||||
<button type="submit" form="quickBookingForm" class="btn btn-primary">
|
||||
<i class="fas fa-credit-card me-1"></i>Забронировать
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
document.body.appendChild(modal);
|
||||
|
||||
const bootstrapModal = new bootstrap.Modal(modal);
|
||||
bootstrapModal.show();
|
||||
|
||||
// Удаление модального окна после закрытия
|
||||
modal.addEventListener('hidden.bs.modal', function() {
|
||||
document.body.removeChild(modal);
|
||||
});
|
||||
}
|
||||
|
||||
// Делаем функции доступными глобально для использования в компонентах
|
||||
window.clearSearchResults = clearSearchResults;
|
||||
window.quickBookTour = quickBookTour;
|
||||
|
||||
// ==========================================
|
||||
// Утилитарные функции (продолжение)
|
||||
// ==========================================
|
||||
|
||||
// ==========================================
|
||||
// Финальные утилитарные функции
|
||||
// ==========================================
|
||||
function createAlertContainer() {
|
||||
const container = document.createElement('div');
|
||||
container.id = 'alert-container';
|
||||
@@ -387,5 +576,13 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
return container;
|
||||
}
|
||||
|
||||
console.log('Korea Tourism Agency - JavaScript loaded successfully! 🇰🇷');
|
||||
// Функция для форматирования чисел (валюта)
|
||||
function formatNumber(num) {
|
||||
return new Intl.NumberFormat('ru-RU').format(num);
|
||||
}
|
||||
|
||||
// Делаем утилитарные функции доступными глобально
|
||||
window.formatNumber = formatNumber;
|
||||
|
||||
console.log('Korea Tourism Agency - JavaScript with components loaded successfully! 🇰🇷');
|
||||
});
|
||||
Reference in New Issue
Block a user