Files
hotell777_260507/public/js/main.js
2026-05-11 16:31:22 +05:00

333 lines
11 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Preloader
window.addEventListener('load', () => {
setTimeout(() => {
document.getElementById('preloader').classList.add('hidden');
}, 1500);
});
// Navbar scroll effect
const navbar = document.querySelector('.navbar');
window.addEventListener('scroll', () => {
if (window.scrollY > 80) {
navbar.classList.add('scrolled');
} else {
navbar.classList.remove('scrolled');
}
});
// Scroll animations
const observerOptions = {
threshold: 0.1,
rootMargin: '0px 0px -50px 0px'
};
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('animated');
}
});
}, observerOptions);
document.querySelectorAll('.animate-on-scroll').forEach(el => {
observer.observe(el);
});
// Counter animation
const counterObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const counters = entry.target.querySelectorAll('.counter');
counters.forEach(counter => {
const target = parseInt(counter.getAttribute('data-target'));
const duration = 2000;
const step = target / (duration / 16);
let current = 0;
const timer = setInterval(() => {
current += step;
if (current >= target) {
counter.textContent = target;
clearInterval(timer);
} else {
counter.textContent = Math.floor(current);
}
}, 16);
});
counterObserver.unobserve(entry.target);
}
});
}, { threshold: 0.5 });
const statsSection = document.querySelector('.hero-stats');
if (statsSection) counterObserver.observe(statsSection);
// Set min date for checkin to today
const today = new Date().toISOString().split('T')[0];
document.querySelector('[name="checkin"]').min = today;
document.querySelector('[name="checkout"]').min = today;
// Booking modal - set room name
document.querySelectorAll('.btn-book').forEach(btn => {
btn.addEventListener('click', function() {
const room = this.getAttribute('data-room');
document.getElementById('selectedRoom').value = room;
const maxGuests = parseInt(this.getAttribute('data-max-guests')) || ROOM_MAX_GUESTS[room] || 4;
updateGuestOptionsFallback(room);
hidePriceInfo();
});
});
function updateGuestOptionsDynamic(roomType, maxGuests) {
const guestsSelect = document.querySelector('[name="guests"]');
if (!guestsSelect) return;
let options = [];
for (let i = 1; i <= maxGuests; i++) {
let text = i === 1 ? '1 гость' : (i < 5 ? `${i} гостя` : `${i} гостей`);
options.push(`<option value="${i}">${text}</option>`);
}
guestsSelect.innerHTML = options.join('');
}
window.updateRoomPricesData = function(prices, maxGuests) {
Object.assign(ROOM_PRICES, prices);
Object.assign(ROOM_MAX_GUESTS, maxGuests);
};
function updateGuestOptions(room) {
const guestsSelect = document.querySelector('[name="guests"]');
if (!guestsSelect) return;
const maxGuests = ROOM_MAX_GUESTS[room] || 4;
let options = [];
for (let i = 1; i <= maxGuests; i++) {
let text = i === 1 ? '1 гость' : (i < 5 ? `${i} гостя` : `${i} гостей`);
options.push(`<option value="${i}">${text}</option>`);
}
guestsSelect.innerHTML = options.join('');
}
function updateGuestOptionsFallback(room) {
const guestsSelect = document.querySelector('[name="guests"]');
if (!guestsSelect) return;
const options2x = [
{ value: 1, text: '1 гость' },
{ value: 2, text: '2 гостя' }
];
const options3x = [
{ value: 1, text: '1 гость' },
{ value: 2, text: '2 гостя' },
{ value: 3, text: '3 гостя' }
];
const optionsDefault = [
{ value: 1, text: '1 гость' },
{ value: 2, text: '2 гостя' },
{ value: 3, text: '3 гостя' },
{ value: 4, text: '4 гостя' }
];
let options = optionsDefault;
if (room === '2x-местный') options = options2x;
else if (room === '3х-местный') options = options3x;
guestsSelect.innerHTML = options.map(o => `<option value="${o.value}">${o.text}</option>`).join('');
}
function hideGuestOptionsUpdate() {}
// Price calculation
const ROOM_PRICES = { '2x-местный': 1500, '3х-местный': 2000, 'Семейный': 3000, 'Люкс': 4500 };
const ROOM_MAX_GUESTS = { '2x-местный': 2, '3х-местный': 3, 'Семейный': 4, 'Люкс': 4 };
let currentPromocodeData = null;
function calculateNights(checkin, checkout) {
const ci = new Date(checkin);
const co = new Date(checkout);
return Math.ceil((co - ci) / (1000 * 60 * 60 * 24));
}
function validateBookingDates() {
const checkinInput = document.querySelector('[name="checkin"]');
const checkoutInput = document.querySelector('[name="checkout"]');
const today = new Date();
today.setHours(0, 0, 0, 0);
if (checkinInput.value) {
const checkinDate = new Date(checkinInput.value);
if (checkinDate < today) {
checkinInput.setCustomValidity('Дата заезда не может быть в прошлом');
} else {
checkinInput.setCustomValidity('');
}
}
if (checkinInput.value && checkoutInput.value) {
const checkinDate = new Date(checkinInput.value);
const checkoutDate = new Date(checkoutInput.value);
if (checkoutDate <= checkinDate) {
checkoutInput.setCustomValidity('Дата выезда должна быть позже даты заезда');
} else {
checkoutInput.setCustomValidity('');
}
}
return checkinInput.checkValidity() && checkoutInput.checkValidity();
}
document.querySelector('[name="checkin"]').addEventListener('change', validateBookingDates);
document.querySelector('[name="checkout"]').addEventListener('change', validateBookingDates);
function updatePriceDisplay(basePrice, discountPercent, discountAmount, totalPrice) {
document.getElementById('basePriceDisplay').textContent = basePrice + ' ₽';
document.getElementById('discountPercentDisplay').textContent = discountPercent;
document.getElementById('discountAmountDisplay').textContent = '-' + discountAmount + ' ₽';
document.getElementById('totalPriceDisplay').textContent = totalPrice + ' ₽';
document.getElementById('priceInfo').style.display = 'block';
}
function hidePriceInfo() {
document.getElementById('priceInfo').style.display = 'none';
currentPromocodeData = null;
}
function getFormData() {
return {
room: document.getElementById('selectedRoom').value,
checkin: document.querySelector('[name="checkin"]').value,
checkout: document.querySelector('[name="checkout"]').value,
promocode: document.getElementById('promocodeInput').value.trim()
};
}
async function checkPromocode() {
const { room, checkin, checkout, promocode } = getFormData();
if (!room || !checkin || !checkout) {
hidePriceInfo();
return;
}
const basePrice = ROOM_PRICES[room] ? ROOM_PRICES[room] * calculateNights(checkin, checkout) : 0;
if (!promocode) {
updatePriceDisplay(basePrice, 0, 0, basePrice);
currentPromocodeData = null;
return;
}
try {
const response = await fetch('/api/promocodes/validate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ code: promocode, room_type: room, checkin, checkout })
});
const data = await response.json();
if (data.valid) {
currentPromocodeData = data;
updatePriceDisplay(data.base_price, data.discount_percent, data.discount_amount, data.total_price);
} else {
hidePriceInfo();
currentPromocodeData = null;
}
} catch (error) {
console.error('Promocode validation error:', error);
hidePriceInfo();
}
}
document.getElementById('checkPromocodeBtn').addEventListener('click', checkPromocode);
document.getElementById('promocodeInput').addEventListener('blur', checkPromocode);
document.querySelector('[name="checkin"]').addEventListener('change', checkPromocode);
document.querySelector('[name="checkout"]').addEventListener('change', checkPromocode);
document.querySelectorAll('.btn-book').forEach(btn => {
btn.addEventListener('click', function() {
setTimeout(checkPromocode, 100);
});
});
// Form submission
document.getElementById('bookingForm').addEventListener('submit', async function(e) {
e.preventDefault();
const btn = this.querySelector('.btn-submit-booking');
const originalText = btn.innerHTML;
btn.innerHTML = '<i class="fas fa-spinner fa-spin me-2"></i>Отправка...';
btn.disabled = true;
const formData = {
name: this.querySelector('[name="name"]').value,
phone: this.querySelector('[name="phone"]').value,
adults: parseInt(this.querySelector('[name="guests"]').value),
children: 0,
checkin: this.querySelector('[name="checkin"]').value,
checkout: this.querySelector('[name="checkout"]').value,
wishes: this.querySelector('[name="wishes"]').value,
room: document.getElementById('selectedRoom').value,
promocode: document.getElementById('promocodeInput').value.trim() || null
};
try {
const response = await fetch('/api/bookings', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(formData)
});
if (response.ok) {
btn.innerHTML = '<i class="fas fa-check me-2"></i>Заявка отправлена Рауфу Алексеевичу!';
btn.style.background = '#25d366';
this.reset();
hidePriceInfo();
setTimeout(() => {
btn.innerHTML = originalText;
btn.style.background = '';
btn.disabled = false;
bootstrap.Modal.getInstance(document.getElementById('bookingModal')).hide();
}, 2500);
} else {
const errorData = await response.json();
throw new Error(errorData.error || 'Ошибка сервера');
}
} catch (error) {
console.error('Booking error:', error);
btn.innerHTML = '<i class="fas fa-exclamation-triangle me-2"></i>Ошибка отправки';
btn.style.background = '#c9302c';
setTimeout(() => {
btn.innerHTML = originalText;
btn.style.background = '';
btn.disabled = false;
}, 3000);
}
});
// Smooth scroll for nav links
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', function(e) {
e.preventDefault();
const target = document.querySelector(this.getAttribute('href'));
if (target) {
target.scrollIntoView({ behavior: 'smooth', block: 'start' });
// Close mobile menu
const navCollapse = document.querySelector('.navbar-collapse');
if (navCollapse.classList.contains('show')) {
bootstrap.Collapse.getInstance(navCollapse).hide();
}
}
});
});
// Parallax effect on hero
window.addEventListener('scroll', () => {
const hero = document.querySelector('.hero-bg');
if (hero) {
const scrolled = window.scrollY;
hero.style.transform = `scale(${1 + scrolled * 0.0001}) translateY(${scrolled * 0.3}px)`;
}
});