Files
dostavka_vodi/index3.js
2026-04-04 19:58:19 +03:00

335 lines
12 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.

const audienceContent = {
home: 'Артезианская вода 19 литров с доставкой на дом и в офис. Привозим по Гагаринскому, Ленинскому, Нахимовскому и Балаклавскому районам, помогаем с возвратной тарой и держим понятные цены без скрытых доплат.',
office: 'Доставка воды в офис в Севастополе с регулярным графиком, безналичной оплатой и приоритетными интервалами. Подходит для команд, кафе, студий, фитнес-клубов и клиентских пространств.'
}
const audienceButtons = document.querySelectorAll('[data-audience]')
const heroAudienceText = document.getElementById('heroAudienceText')
const mobileToggle = document.getElementById('mobileToggle')
const mobilePanel = document.getElementById('mobilePanel')
const cartDrawer = document.getElementById('cartDrawer')
const cartOpenButton = document.getElementById('cartOpenButton')
const mobileCartOpenButton = document.getElementById('mobileCartOpenButton')
const cartCloseButton = document.getElementById('cartCloseButton')
const modalBackdrop = document.getElementById('orderModal')
const modalCloseButton = document.getElementById('modalCloseButton')
const viewCartButton = document.getElementById('viewCartButton')
const checkoutButton = document.getElementById('checkoutButton')
const orderButtons = document.querySelectorAll('[data-open-order]')
const addToCartButtons = document.querySelectorAll('.add-to-cart')
const faqItems = document.querySelectorAll('.faq-item')
const cartCount = document.getElementById('cartCount')
const mobileCartCount = document.getElementById('mobileCartCount')
const cartItemsCount = document.getElementById('cartItemsCount')
const cartTotal = document.getElementById('cartTotal')
const cartList = document.getElementById('cartList')
const orderForm = document.getElementById('orderForm')
const contactForm = document.getElementById('contactForm')
const orderItemsField = document.getElementById('orderItemsField')
const orderSuccess = document.getElementById('orderSuccess')
const contactSuccess = document.getElementById('contactSuccess')
const wooCommerceConfig = window.test1WooCommerce || null
const cartPanel = cartDrawer?.querySelector('.cart-panel')
const modalCard = modalBackdrop?.querySelector('.modal-card')
let cart = []
let lastCartTrigger = null
let lastModalTrigger = null
const getFocusableElements = container => {
if (!container) {
return []
}
return Array.from(container.querySelectorAll('a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])'))
.filter(element => !element.hasAttribute('hidden') && !element.closest('[hidden]'))
}
const focusFirstElement = container => {
const [first] = getFocusableElements(container)
if (first) {
first.focus()
}
}
const updateAudience = audience => {
heroAudienceText.textContent = audienceContent[audience]
audienceButtons.forEach(button => {
const isActive = button.dataset.audience === audience
button.classList.toggle('active', isActive)
button.setAttribute('aria-selected', String(isActive))
})
const typeField = orderForm.elements.customerType
typeField.value = audience === 'office' ? 'Для офиса' : 'Для дома'
}
const openMobileMenu = () => {
mobilePanel.classList.add('active')
mobileToggle.setAttribute('aria-expanded', 'true')
document.body.classList.add('menu-open')
}
const closeMobileMenu = () => {
mobilePanel.classList.remove('active')
mobileToggle.setAttribute('aria-expanded', 'false')
document.body.classList.remove('menu-open')
}
const openCart = triggerElement => {
lastCartTrigger = triggerElement || document.activeElement
cartDrawer.classList.add('open')
cartDrawer.setAttribute('aria-hidden', 'false')
document.body.classList.add('modal-open')
focusFirstElement(cartPanel)
}
const closeCart = () => {
const shouldRestoreFocus = cartDrawer.classList.contains('open')
cartDrawer.classList.remove('open')
cartDrawer.setAttribute('aria-hidden', 'true')
document.body.classList.remove('modal-open')
if (shouldRestoreFocus && lastCartTrigger && typeof lastCartTrigger.focus === 'function') {
lastCartTrigger.focus()
}
lastCartTrigger = null
}
const openModal = triggerElement => {
lastModalTrigger = triggerElement || document.activeElement
orderItemsField.value = cart.length
? cart.map(item => `${item.name} (${item.volume}) - ${item.price}`).join('\n')
: ''
modalBackdrop.classList.add('open')
modalBackdrop.setAttribute('aria-hidden', 'false')
document.body.classList.add('modal-open')
focusFirstElement(modalCard)
}
const closeModal = () => {
const shouldRestoreFocus = modalBackdrop.classList.contains('open')
modalBackdrop.classList.remove('open')
modalBackdrop.setAttribute('aria-hidden', 'true')
document.body.classList.remove('modal-open')
if (shouldRestoreFocus && lastModalTrigger && typeof lastModalTrigger.focus === 'function') {
lastModalTrigger.focus()
}
lastModalTrigger = null
}
const renderCart = () => {
const total = cart.reduce((sum, item) => sum + item.price, 0)
const count = cart.length
cartCount.textContent = count
mobileCartCount.textContent = count
cartItemsCount.textContent = count
cartTotal.textContent = `${total}`
if (!count) {
cartList.innerHTML = '<div class="empty-state">Корзина пока пуста. Добавьте воду 19 литров, компактные форматы или минеральную воду из каталога.</div>'
return
}
cartList.innerHTML = cart.map((item, index) => `
<div class="cart-item">
<div>
<strong>${item.name}</strong>
<span>${item.volume} · ${item.price} ₽</span>
</div>
<button type="button" data-remove-index="${index}" aria-label="Удалить ${item.name} из корзины">Удалить</button>
</div>
`).join('')
cartList.querySelectorAll('[data-remove-index]').forEach(button => {
button.addEventListener('click', () => {
const index = Number(button.dataset.removeIndex)
cart.splice(index, 1)
renderCart()
})
})
}
audienceButtons.forEach(button => {
button.addEventListener('click', () => updateAudience(button.dataset.audience))
})
mobileToggle.addEventListener('click', () => {
const isOpen = mobilePanel.classList.contains('active')
if (isOpen) {
closeMobileMenu()
return
}
openMobileMenu()
})
document.querySelectorAll('.mobile-nav a').forEach(link => {
link.addEventListener('click', closeMobileMenu)
})
addToCartButtons.forEach(button => {
button.addEventListener('click', () => {
const productId = Number(button.dataset.productId || 0)
if (wooCommerceConfig && productId && wooCommerceConfig.addToCartUrl && wooCommerceConfig.checkoutUrl) {
button.disabled = true
fetch(wooCommerceConfig.addToCartUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
},
body: new URLSearchParams({
product_id: String(productId),
quantity: '1'
})
})
.then(async response => {
let payload = null
try {
payload = await response.json()
} catch (error) {
payload = null
}
if (!response.ok) {
throw new Error('add_to_cart_failed')
}
if (payload && payload.error && payload.product_url) {
window.location.href = payload.product_url
return
}
cart.push({
name: button.dataset.name,
volume: button.dataset.volume,
price: Number(button.dataset.price)
})
renderCart()
openCart(button)
button.disabled = false
})
.catch(() => {
button.disabled = false
})
return
}
cart.push({
name: button.dataset.name,
volume: button.dataset.volume,
price: Number(button.dataset.price)
})
renderCart()
openCart(button)
})
})
cartOpenButton.addEventListener('click', () => openCart(cartOpenButton))
mobileCartOpenButton.addEventListener('click', () => {
closeMobileMenu()
openCart(mobileCartOpenButton)
})
cartCloseButton.addEventListener('click', closeCart)
viewCartButton.addEventListener('click', () => {
if (wooCommerceConfig && wooCommerceConfig.cartUrl) {
window.location.href = wooCommerceConfig.cartUrl
}
})
checkoutButton.addEventListener('click', () => {
if (wooCommerceConfig && wooCommerceConfig.checkoutUrl) {
window.location.href = wooCommerceConfig.checkoutUrl
return
}
closeCart()
openModal(checkoutButton)
})
orderButtons.forEach(button => {
button.addEventListener('click', () => openModal(button))
})
modalCloseButton.addEventListener('click', closeModal)
cartDrawer.addEventListener('click', event => {
if (event.target === cartDrawer) {
closeCart()
}
})
modalBackdrop.addEventListener('click', event => {
if (event.target === modalBackdrop) {
closeModal()
}
})
faqItems.forEach(item => {
const trigger = item.querySelector('.faq-question')
const answer = item.querySelector('.faq-answer')
if (!trigger || !answer) {
return
}
trigger.addEventListener('click', () => {
const isOpen = item.classList.contains('open')
faqItems.forEach(entry => {
const entryTrigger = entry.querySelector('.faq-question')
const entryAnswer = entry.querySelector('.faq-answer')
entry.classList.remove('open')
entryTrigger?.setAttribute('aria-expanded', 'false')
if (entryAnswer) {
entryAnswer.hidden = true
}
})
if (!isOpen) {
item.classList.add('open')
trigger.setAttribute('aria-expanded', 'true')
answer.hidden = false
}
})
})
orderForm.addEventListener('submit', event => {
event.preventDefault()
orderSuccess.classList.add('visible')
cart = []
renderCart()
setTimeout(() => {
closeModal()
orderForm.reset()
orderSuccess.classList.remove('visible')
}, 1800)
})
contactForm.addEventListener('submit', event => {
event.preventDefault()
contactSuccess.classList.add('visible')
setTimeout(() => {
contactForm.reset()
contactSuccess.classList.remove('visible')
}, 2200)
})
document.addEventListener('keydown', event => {
if (event.key !== 'Escape') {
return
}
closeCart()
closeModal()
closeMobileMenu()
})
renderCart()
updateAudience('home')