724 lines
32 KiB
PHP
724 lines
32 KiB
PHP
<?php
|
||
|
||
declare(strict_types=1);
|
||
|
||
/** @var string $templatePath */
|
||
/** @var string $title */
|
||
/** @var string $metaDescription */
|
||
/** @var string $metaKeywords */
|
||
/** @var array<int, array{title: string, url?: string}> $breadcrumbs */
|
||
/** @var bool $showBackButton */
|
||
$megaCategories = [];
|
||
|
||
try {
|
||
$megaCategories = (new \App\Repositories\CategoryRepository())->tree();
|
||
} catch (\Throwable) {
|
||
$megaCategories = [];
|
||
}
|
||
?>
|
||
<!doctype html>
|
||
<html lang="ru">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<title><?= e($title) ?></title>
|
||
<?php if ($metaDescription !== ''): ?>
|
||
<meta name="description" content="<?= e($metaDescription) ?>">
|
||
<?php endif; ?>
|
||
<?php if ($metaKeywords !== ''): ?>
|
||
<meta name="keywords" content="<?= e($metaKeywords) ?>">
|
||
<?php endif; ?>
|
||
<link rel="stylesheet" href="/assets/css/app.css">
|
||
</head>
|
||
<body>
|
||
<header class="site-topbar">
|
||
<div class="site-topbar-inner">
|
||
<a class="brand-link" href="/">
|
||
<?php if (is_file(base_path('public/assets/images/logo-rybstock.svg'))): ?>
|
||
<img src="/assets/images/logo-rybstock.svg" alt="Рыбсток">
|
||
<?php else: ?>
|
||
<span>РЫБ<span>СТОК</span></span>
|
||
<small>Качественные продукты по стоковым ценам</small>
|
||
<?php endif; ?>
|
||
</a>
|
||
<nav class="main-nav" aria-label="Главное меню">
|
||
<a href="/">Главная</a>
|
||
<a href="/catalog">Каталог</a>
|
||
<a href="/delivery">Доставка</a>
|
||
<a href="/contacts">Контакты</a>
|
||
<a class="cart-link" href="/cart">Корзина <span data-cart-count hidden>0</span></a>
|
||
</nav>
|
||
<div class="topbar-contacts">
|
||
<a href="tel:+79777363363">+7-977-736-33-63</a>
|
||
<span>Самовывоз: г. Москва, ул. Привольная, д. 13к1</span>
|
||
</div>
|
||
</div>
|
||
</header>
|
||
|
||
<section class="smart-search-bar" aria-label="Поиск по каталогу">
|
||
<div class="smart-search-inner">
|
||
<form class="smart-search-form" action="/catalog" method="get">
|
||
<label class="smart-search-label" for="site-search">Умный поиск</label>
|
||
<div class="smart-search-control">
|
||
<input id="site-search" name="q" type="search" placeholder="Например: форель стейки, креветки 1 кг, красная рыба, что взять на ужин">
|
||
<button class="voice-search-button" type="button" aria-label="Голосовой ввод" title="Голосовой ввод">Голос</button>
|
||
<button class="smart-search-submit" type="submit">Найти</button>
|
||
</div>
|
||
<p>Понимает склонения, похожие запросы и бытовые формулировки. Обучаемый поиск подключим к товарам после загрузки каталога.</p>
|
||
</form>
|
||
</div>
|
||
</section>
|
||
|
||
<?php require base_path('views/partials/mega-category-menu.php'); ?>
|
||
|
||
<section class="price-mode-bar" aria-label="Система оплаты при получении">
|
||
<div class="price-mode-inner">
|
||
<span>Выберите систему оплаты при получении:</span>
|
||
<div class="price-mode-options" role="group" aria-label="Способ оплаты">
|
||
<button type="button" class="price-mode-button price-mode-button-cash is-active" data-payment-mode="cash">
|
||
<span>Наличными</span>
|
||
<b>Выгодно от 7000р.</b>
|
||
</button>
|
||
<button type="button" class="price-mode-button" data-payment-mode="qr">QR-код</button>
|
||
<button type="button" class="price-mode-button" data-payment-mode="invoice">Расчетный счет</button>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<header class="site-utility">
|
||
<?php if ($showBackButton): ?>
|
||
<button class="back-button" type="button" onclick="history.length > 1 ? history.back() : location.href='/'">Вернуться назад</button>
|
||
<?php endif; ?>
|
||
|
||
<?php require base_path('views/partials/breadcrumbs.php'); ?>
|
||
</header>
|
||
|
||
<main class="page">
|
||
<?php require $templatePath; ?>
|
||
</main>
|
||
|
||
<footer class="site-footer">
|
||
<div class="site-footer-inner">
|
||
<section class="footer-brand">
|
||
<a class="footer-logo" href="/">
|
||
<?php if (is_file(base_path('public/assets/images/logo-rybstock.svg'))): ?>
|
||
<img src="/assets/images/logo-rybstock.svg" alt="Рыбсток">
|
||
<?php else: ?>
|
||
<span>Рыбсток</span>
|
||
<?php endif; ?>
|
||
</a>
|
||
</section>
|
||
|
||
<section class="footer-column">
|
||
<h2>Контакты</h2>
|
||
<dl class="footer-contacts">
|
||
<div>
|
||
<dt>Телефон</dt>
|
||
<dd><a href="tel:+79777363363">+7-977-736-33-63</a></dd>
|
||
</div>
|
||
<div>
|
||
<dt>Email</dt>
|
||
<dd><a href="mailto:zakaz@rybstock.ru">zakaz@rybstock.ru</a></dd>
|
||
</div>
|
||
<div>
|
||
<dt>Адрес самовывоза</dt>
|
||
<dd>г. Москва, ул. Привольная, д. 13к1</dd>
|
||
</div>
|
||
</dl>
|
||
</section>
|
||
|
||
<nav class="footer-column footer-links" aria-label="Ссылки в подвале">
|
||
<h2>Покупателям</h2>
|
||
<a href="/">Главная</a>
|
||
<a href="/catalog">Каталог</a>
|
||
<a href="/delivery">Доставка</a>
|
||
<a href="/payment">Оплата</a>
|
||
<a href="/reviews">Отзывы</a>
|
||
<a href="/returns">Правила возврата товара</a>
|
||
</nav>
|
||
|
||
<section class="footer-column">
|
||
<h2>Заказы</h2>
|
||
<p>Доставка и самовывоз происходят после подтверждения заказа по телефону.</p>
|
||
<a class="footer-action" href="/catalog">Перейти в каталог</a>
|
||
</section>
|
||
</div>
|
||
|
||
<div class="site-footer-bottom">
|
||
<p>© 2026 Рыбсток</p>
|
||
<p>Информация на сайте носит справочный характер и не является публичной офертой. Наличие, фасовки, цены и условия доставки подтверждаются менеджером при обработке заказа.</p>
|
||
</div>
|
||
</footer>
|
||
<script>
|
||
(() => {
|
||
const button = document.querySelector('.voice-search-button');
|
||
const input = document.querySelector('#site-search');
|
||
const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
|
||
|
||
if (!button || !input) {
|
||
return;
|
||
}
|
||
|
||
if (!SpeechRecognition) {
|
||
button.addEventListener('click', () => {
|
||
input.focus();
|
||
input.placeholder = 'Голосовой ввод не поддерживается этим браузером';
|
||
});
|
||
return;
|
||
}
|
||
|
||
const recognition = new SpeechRecognition();
|
||
recognition.lang = 'ru-RU';
|
||
recognition.interimResults = false;
|
||
|
||
button.addEventListener('click', () => {
|
||
button.classList.add('is-listening');
|
||
recognition.start();
|
||
});
|
||
|
||
recognition.addEventListener('result', (event) => {
|
||
const phrase = event.results[0]?.[0]?.transcript || '';
|
||
input.value = phrase;
|
||
input.focus();
|
||
});
|
||
|
||
recognition.addEventListener('end', () => {
|
||
button.classList.remove('is-listening');
|
||
});
|
||
})();
|
||
(() => {
|
||
const nodes = document.querySelectorAll('[data-temperature]');
|
||
|
||
if (nodes.length === 0) {
|
||
return;
|
||
}
|
||
|
||
const clamp = (value, min, max) => Math.min(max, Math.max(min, value));
|
||
|
||
nodes.forEach((node) => {
|
||
let current = Number(node.dataset.temperature || node.textContent || 0);
|
||
const min = Number(node.dataset.min || current - 1);
|
||
const max = Number(node.dataset.max || current + 1);
|
||
|
||
const update = () => {
|
||
const drift = (Math.random() - 0.5) * 0.28;
|
||
current = clamp(current + drift, min, max);
|
||
node.textContent = current.toFixed(1);
|
||
};
|
||
|
||
window.setInterval(update, 4200 + Math.random() * 2400);
|
||
});
|
||
})();
|
||
(() => {
|
||
const formatRub = (value) => new Intl.NumberFormat('ru-RU').format(Math.max(0, Math.floor(Number(value) || 0))) + ' руб.';
|
||
const storageKeys = {
|
||
paymentMode: 'rybstock_payment_mode',
|
||
cartTotal: 'rybstock_cart_total',
|
||
cartItems: 'rybstock_cart_items'
|
||
};
|
||
|
||
const getPaymentMode = () => localStorage.getItem(storageKeys.paymentMode) || 'cash';
|
||
const getCartTotal = () => Number(localStorage.getItem(storageKeys.cartTotal) || 0);
|
||
const getCartItems = () => {
|
||
try {
|
||
const items = JSON.parse(localStorage.getItem(storageKeys.cartItems) || '[]');
|
||
return Array.isArray(items) ? items : [];
|
||
} catch (error) {
|
||
return [];
|
||
}
|
||
};
|
||
const cartBaseTotal = (items = getCartItems()) => items.reduce((sum, item) => {
|
||
return sum + (Number(item.basePackagePrice || 0) * Number(item.quantity || 0));
|
||
}, 0);
|
||
const saveCartItems = (items) => {
|
||
localStorage.setItem(storageKeys.cartItems, JSON.stringify(items));
|
||
localStorage.setItem(storageKeys.cartTotal, String(cartBaseTotal(items)));
|
||
};
|
||
const escapeHtml = (value) => String(value ?? '').replace(/[&<>"']/g, (char) => ({
|
||
'&': '&',
|
||
'<': '<',
|
||
'>': '>',
|
||
'"': '"',
|
||
"'": '''
|
||
})[char]);
|
||
|
||
const priceMode = () => {
|
||
const payment = getPaymentMode();
|
||
const total = getCartTotal();
|
||
|
||
if (payment === 'invoice') {
|
||
return { multiplier: 1.08, fixedDiscount: 0, label: 'Оплата по расчетному счету: +8%' };
|
||
}
|
||
|
||
if (payment === 'qr') {
|
||
return { multiplier: 1, fixedDiscount: 0, label: 'QR-код: базовая цена' };
|
||
}
|
||
|
||
if (total >= 50000) {
|
||
return { multiplier: 0.93, fixedDiscount: 0, label: 'Наличные: цена от 50 000р.' };
|
||
}
|
||
|
||
if (total >= 20000) {
|
||
return { multiplier: 0.95, fixedDiscount: 0, label: 'Наличные: цена от 20 000р.' };
|
||
}
|
||
|
||
if (total >= 7000) {
|
||
return { multiplier: 1, fixedDiscount: 300, label: 'Наличные: -300р. от 7000р.' };
|
||
}
|
||
|
||
return { multiplier: 1, fixedDiscount: 0, label: 'Наличные: базовая цена до 7000р.' };
|
||
};
|
||
|
||
const cartCurrentTotal = (items = getCartItems()) => {
|
||
const mode = priceMode();
|
||
const subtotal = Math.floor(cartBaseTotal(items) * mode.multiplier);
|
||
|
||
return Math.max(0, subtotal - Number(mode.fixedDiscount || 0));
|
||
};
|
||
|
||
const tierValues = (base) => ({
|
||
base: base,
|
||
cash20: base * 0.95,
|
||
cash50: base * 0.93
|
||
});
|
||
|
||
const updateDynamicPrices = (scope) => {
|
||
const mode = priceMode();
|
||
|
||
scope.querySelectorAll('[data-dynamic-package-price]').forEach((node) => {
|
||
const base = Number(node.dataset.basePackagePrice || 0);
|
||
node.textContent = formatRub(base * mode.multiplier);
|
||
});
|
||
|
||
scope.querySelectorAll('[data-dynamic-unit-price]').forEach((node) => {
|
||
const base = Number(node.dataset.baseUnitPrice || 0);
|
||
if (base > 0) {
|
||
node.textContent = formatRub(base * mode.multiplier);
|
||
}
|
||
});
|
||
};
|
||
|
||
const updateCardPrices = (card) => {
|
||
const packageNode = card.querySelector('[data-dynamic-package-price]');
|
||
const unitNode = card.querySelector('[data-dynamic-unit-price]');
|
||
updateDynamicPrices(card);
|
||
|
||
if (unitNode || packageNode) {
|
||
const unitBase = Number(unitNode?.dataset.baseUnitPrice || 0);
|
||
const packageBase = Number(packageNode?.dataset.basePackagePrice || 0);
|
||
const unitPriceRow = card.querySelector('[data-unit-price-row]');
|
||
const showUnitPrice = card.dataset.showUnitPrice === '1' && !unitPriceRow?.classList.contains('is-price-placeholder');
|
||
const base = showUnitPrice && unitBase > 0 ? unitBase : packageBase;
|
||
|
||
const tiers = tierValues(base);
|
||
const tierBase = card.querySelector('[data-tier-base]');
|
||
const tierCash20 = card.querySelector('[data-tier-cash-20]');
|
||
const tierCash50 = card.querySelector('[data-tier-cash-50]');
|
||
const tierUnitLabel = card.querySelector('[data-tier-unit-label]');
|
||
|
||
if (tierBase) tierBase.textContent = formatRub(tiers.base);
|
||
if (tierCash20) tierCash20.textContent = formatRub(tiers.cash20);
|
||
if (tierCash50) tierCash50.textContent = formatRub(tiers.cash50);
|
||
if (tierUnitLabel) tierUnitLabel.textContent = showUnitPrice
|
||
? (card.querySelector('[data-unit-label]')?.textContent || 'кг')
|
||
: 'фасовку';
|
||
}
|
||
|
||
};
|
||
|
||
const updateCartCount = () => {
|
||
const count = getCartItems().reduce((sum, item) => sum + Number(item.quantity || 0), 0);
|
||
|
||
document.querySelectorAll('[data-cart-count]').forEach((node) => {
|
||
node.textContent = String(count);
|
||
node.hidden = count === 0;
|
||
});
|
||
};
|
||
|
||
const updateMiniCart = () => {
|
||
const items = getCartItems();
|
||
const count = items.reduce((sum, item) => sum + Number(item.quantity || 0), 0);
|
||
const total = cartCurrentTotal(items);
|
||
|
||
document.querySelectorAll('[data-mini-cart-count]').forEach((node) => {
|
||
node.textContent = String(count);
|
||
});
|
||
|
||
document.querySelectorAll('[data-mini-cart-total]').forEach((node) => {
|
||
node.textContent = formatRub(total);
|
||
});
|
||
};
|
||
|
||
const itemCurrentPrice = (item) => Math.floor(Number(item.basePackagePrice || 0) * priceMode().multiplier);
|
||
|
||
const renderCartPage = () => {
|
||
const cartPage = document.querySelector('[data-cart-page]');
|
||
|
||
if (!cartPage) {
|
||
return;
|
||
}
|
||
|
||
const itemsNode = cartPage.querySelector('[data-cart-items]');
|
||
const emptyNode = cartPage.querySelector('[data-cart-empty]');
|
||
const baseTotalNode = cartPage.querySelector('[data-cart-base-total]');
|
||
const totalNode = cartPage.querySelector('[data-cart-current-total]');
|
||
const modeNode = cartPage.querySelector('[data-cart-current-mode]');
|
||
const savingRow = cartPage.querySelector('[data-cart-saving-row]');
|
||
const savingNode = cartPage.querySelector('[data-cart-saving-total]');
|
||
const items = getCartItems();
|
||
const baseTotal = cartBaseTotal(items);
|
||
const currentTotal = cartCurrentTotal(items);
|
||
const savingTotal = Math.max(0, baseTotal - currentTotal);
|
||
|
||
if (emptyNode) {
|
||
emptyNode.hidden = items.length !== 0;
|
||
}
|
||
|
||
if (itemsNode) {
|
||
itemsNode.innerHTML = '';
|
||
|
||
items.forEach((item) => {
|
||
const row = document.createElement('article');
|
||
row.className = 'cart-row';
|
||
row.dataset.cartKey = item.key;
|
||
row.innerHTML = `
|
||
<div class="cart-row-image">${item.image ? `<img src="${escapeHtml(item.image)}" alt="">` : ''}</div>
|
||
<div class="cart-row-main">
|
||
<h2>${escapeHtml(item.name)}</h2>
|
||
<p>${escapeHtml(item.variantName || 'Фасовка')} · ${formatRub(itemCurrentPrice(item))} за фасовку</p>
|
||
</div>
|
||
<div class="cart-row-controls">
|
||
<button type="button" data-cart-minus>-</button>
|
||
<strong>${Number(item.quantity || 0)}</strong>
|
||
<button type="button" data-cart-plus>+</button>
|
||
</div>
|
||
<strong class="cart-row-total">${formatRub(itemCurrentPrice(item) * Number(item.quantity || 0))}</strong>
|
||
<button class="cart-row-remove" type="button" data-cart-remove>Убрать</button>
|
||
`;
|
||
itemsNode.append(row);
|
||
});
|
||
}
|
||
|
||
if (baseTotalNode) {
|
||
baseTotalNode.textContent = formatRub(baseTotal);
|
||
}
|
||
|
||
if (totalNode) {
|
||
totalNode.textContent = formatRub(currentTotal);
|
||
}
|
||
|
||
if (modeNode) {
|
||
modeNode.textContent = priceMode().label;
|
||
}
|
||
|
||
if (savingRow) {
|
||
savingRow.hidden = savingTotal <= 0;
|
||
}
|
||
|
||
if (savingNode) {
|
||
savingNode.textContent = formatRub(savingTotal);
|
||
}
|
||
};
|
||
|
||
const updateModeButtons = () => {
|
||
const payment = getPaymentMode();
|
||
document.body.dataset.paymentMode = payment;
|
||
|
||
document.querySelectorAll('[data-payment-mode]').forEach((button) => {
|
||
button.classList.toggle('is-active', button.dataset.paymentMode === payment);
|
||
});
|
||
|
||
};
|
||
|
||
const updateAllPrices = () => {
|
||
updateModeButtons();
|
||
updateCartCount();
|
||
updateMiniCart();
|
||
updateDynamicPrices(document);
|
||
document.querySelectorAll('.product-card.price-aware').forEach(updateCardPrices);
|
||
renderCartPage();
|
||
};
|
||
|
||
window.RybStockPricing = {
|
||
setCartTotal(total) {
|
||
localStorage.setItem(storageKeys.cartTotal, String(Math.max(0, Number(total) || 0)));
|
||
updateAllPrices();
|
||
},
|
||
setPaymentMode(mode) {
|
||
localStorage.setItem(storageKeys.paymentMode, mode);
|
||
updateAllPrices();
|
||
},
|
||
currentMode: priceMode,
|
||
cartBaseTotal,
|
||
cartCurrentTotal,
|
||
update: updateAllPrices
|
||
};
|
||
|
||
const catalogScrollKey = 'rybstock.catalogScrollY';
|
||
const catalogMenuScrollKey = 'rybstock.catalogMenuScrollY';
|
||
|
||
if (window.location.pathname.startsWith('/catalog')) {
|
||
const savedCatalogScroll = sessionStorage.getItem(catalogScrollKey);
|
||
const savedCatalogMenuScroll = sessionStorage.getItem(catalogMenuScrollKey);
|
||
const catalogMenu = document.querySelector('.catalog-menu-panel > .category-list');
|
||
|
||
if (savedCatalogScroll !== null) {
|
||
sessionStorage.removeItem(catalogScrollKey);
|
||
window.requestAnimationFrame(() => {
|
||
window.scrollTo({
|
||
top: Math.max(0, parseInt(savedCatalogScroll, 10) || 0),
|
||
left: 0,
|
||
behavior: 'auto'
|
||
});
|
||
});
|
||
}
|
||
|
||
if (savedCatalogMenuScroll !== null && catalogMenu) {
|
||
sessionStorage.removeItem(catalogMenuScrollKey);
|
||
catalogMenu.scrollTop = Math.max(0, parseInt(savedCatalogMenuScroll, 10) || 0);
|
||
}
|
||
}
|
||
|
||
document.addEventListener('click', (event) => {
|
||
const categoryLink = event.target.closest('.catalog-menu-panel .category-list a[href^="/catalog/"]');
|
||
|
||
if (!categoryLink || event.defaultPrevented || event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) {
|
||
return;
|
||
}
|
||
|
||
sessionStorage.setItem(catalogScrollKey, String(window.scrollY));
|
||
sessionStorage.setItem(catalogMenuScrollKey, String(categoryLink.closest('.catalog-menu-panel > .category-list')?.scrollTop || 0));
|
||
});
|
||
|
||
document.addEventListener('click', (event) => {
|
||
const modeButton = event.target.closest('[data-payment-mode]');
|
||
|
||
if (!modeButton) {
|
||
return;
|
||
}
|
||
|
||
window.RybStockPricing.setPaymentMode(modeButton.dataset.paymentMode || 'cash');
|
||
});
|
||
|
||
document.addEventListener('click', (event) => {
|
||
const quantityButton = event.target.closest('[data-quantity-minus], [data-quantity-plus]');
|
||
|
||
if (!quantityButton) {
|
||
return;
|
||
}
|
||
|
||
const control = quantityButton.closest('[data-quantity-control]');
|
||
const input = control?.querySelector('[data-quantity-input]');
|
||
|
||
if (!input) {
|
||
return;
|
||
}
|
||
|
||
const current = Math.max(1, parseInt(input.value || '1', 10) || 1);
|
||
const next = quantityButton.matches('[data-quantity-plus]')
|
||
? current + 1
|
||
: Math.max(1, current - 1);
|
||
input.value = String(next);
|
||
});
|
||
|
||
document.addEventListener('input', (event) => {
|
||
const input = event.target.closest('[data-quantity-input]');
|
||
|
||
if (!input) {
|
||
return;
|
||
}
|
||
|
||
input.value = String(Math.max(1, parseInt(input.value.replace(/\D/g, '') || '1', 10) || 1));
|
||
});
|
||
|
||
document.addEventListener('click', (event) => {
|
||
const addButton = event.target.closest('.add-to-cart-button');
|
||
|
||
if (!addButton) {
|
||
return;
|
||
}
|
||
|
||
const productScope = addButton.closest('.price-aware');
|
||
const row = addButton.closest('.variant-row');
|
||
const variantButton = productScope?.querySelector('.variant-choice-button.is-active');
|
||
const packagePriceNode = row?.querySelector('[data-dynamic-package-price]') || productScope?.querySelector('[data-dynamic-package-price]');
|
||
const quantityInput = row?.querySelector('[data-quantity-input]') || productScope?.querySelector('[data-quantity-input]');
|
||
|
||
if (!productScope || !packagePriceNode) {
|
||
return;
|
||
}
|
||
|
||
const addQuantity = Math.max(1, parseInt(quantityInput?.value || '1', 10) || 1);
|
||
const variantId = row?.dataset.variantId || variantButton?.dataset.variantId || 'default';
|
||
const key = String(productScope.dataset.productId || '') + ':' + variantId;
|
||
const items = getCartItems();
|
||
const existing = items.find((item) => item.key === key);
|
||
|
||
if (existing) {
|
||
existing.quantity = Number(existing.quantity || 0) + addQuantity;
|
||
} else {
|
||
items.push({
|
||
key,
|
||
productId: productScope.dataset.productId || '',
|
||
slug: productScope.dataset.productSlug || '',
|
||
name: productScope.dataset.productName || '',
|
||
image: productScope.dataset.productImage || '',
|
||
variantId,
|
||
variantName: row?.dataset.variantName || variantButton?.dataset.variantName || 'Фасовка',
|
||
basePackagePrice: Number(packagePriceNode.dataset.basePackagePrice || 0),
|
||
baseUnitPrice: Number(row?.dataset.baseUnitPrice || variantButton?.dataset.baseUnitPrice || 0),
|
||
quantity: addQuantity
|
||
});
|
||
}
|
||
|
||
saveCartItems(items);
|
||
updateAllPrices();
|
||
addButton.classList.add('is-added');
|
||
addButton.textContent = 'Добавлено';
|
||
window.setTimeout(() => {
|
||
addButton.classList.remove('is-added');
|
||
addButton.textContent = 'В корзину';
|
||
}, 1200);
|
||
});
|
||
|
||
document.addEventListener('click', (event) => {
|
||
const notifyButton = event.target.closest('[data-notify-arrival]');
|
||
|
||
if (!notifyButton) {
|
||
return;
|
||
}
|
||
|
||
notifyButton.classList.add('is-sent');
|
||
notifyButton.textContent = 'Запрос принят';
|
||
});
|
||
|
||
document.addEventListener('click', (event) => {
|
||
const control = event.target.closest('[data-cart-plus], [data-cart-minus], [data-cart-remove]');
|
||
|
||
if (!control) {
|
||
return;
|
||
}
|
||
|
||
const row = control.closest('[data-cart-key]');
|
||
const key = row?.dataset.cartKey;
|
||
|
||
if (!key) {
|
||
return;
|
||
}
|
||
|
||
let items = getCartItems();
|
||
const item = items.find((cartItem) => cartItem.key === key);
|
||
|
||
if (!item) {
|
||
return;
|
||
}
|
||
|
||
if (control.matches('[data-cart-plus]')) {
|
||
item.quantity = Number(item.quantity || 0) + 1;
|
||
}
|
||
|
||
if (control.matches('[data-cart-minus]')) {
|
||
item.quantity = Number(item.quantity || 0) - 1;
|
||
}
|
||
|
||
if (control.matches('[data-cart-remove]') || Number(item.quantity || 0) <= 0) {
|
||
items = items.filter((cartItem) => cartItem.key !== key);
|
||
}
|
||
|
||
saveCartItems(items);
|
||
updateAllPrices();
|
||
});
|
||
|
||
document.addEventListener('click', (event) => {
|
||
const button = event.target.closest('.variant-choice-button');
|
||
|
||
if (!button) {
|
||
return;
|
||
}
|
||
|
||
const card = document.getElementById(button.dataset.card || '');
|
||
|
||
if (!card) {
|
||
return;
|
||
}
|
||
|
||
card.querySelectorAll('.variant-choice-button').forEach((item) => {
|
||
item.classList.toggle('is-active', item === button);
|
||
});
|
||
|
||
const unitNode = card.querySelector('[data-unit-label]');
|
||
const unitPriceNode = card.querySelector('[data-dynamic-unit-price]');
|
||
const packagePriceNode = card.querySelector('[data-dynamic-package-price]');
|
||
const packageLabelNode = card.querySelector('[data-package-label-display]');
|
||
const packageLabelNoteNode = card.querySelector('[data-package-label-note]');
|
||
const unitLabelNoteNode = card.querySelector('[data-unit-label-note]');
|
||
const oldPriceNode = card.querySelector('[data-old-package-price-display]');
|
||
const oldUnitPriceNode = card.querySelector('[data-old-unit-price-display]');
|
||
const unitPriceRow = card.querySelector('[data-unit-price-row]');
|
||
const packageTierTrigger = card.querySelector('[data-package-tier-trigger]');
|
||
const packagePriceNote = card.querySelector('[data-package-price-note]');
|
||
const showUnitPrice = button.dataset.showUnitPrice === '1';
|
||
|
||
card.dataset.showUnitPrice = showUnitPrice ? '1' : '0';
|
||
|
||
if (unitPriceRow) {
|
||
unitPriceRow.classList.toggle('is-price-placeholder', !showUnitPrice);
|
||
unitPriceRow.setAttribute('aria-hidden', showUnitPrice ? 'false' : 'true');
|
||
}
|
||
|
||
if (packageTierTrigger) {
|
||
packageTierTrigger.hidden = showUnitPrice;
|
||
}
|
||
|
||
if (packagePriceNote) {
|
||
packagePriceNote.classList.toggle('is-price-placeholder', !showUnitPrice);
|
||
packagePriceNote.setAttribute('aria-hidden', showUnitPrice ? 'false' : 'true');
|
||
}
|
||
|
||
if (unitNode) {
|
||
unitNode.textContent = button.dataset.unit || 'ед.';
|
||
}
|
||
|
||
if (unitLabelNoteNode) {
|
||
unitLabelNoteNode.textContent = button.dataset.unit || 'ед.';
|
||
}
|
||
|
||
if (unitPriceNode) {
|
||
unitPriceNode.dataset.baseUnitPrice = button.dataset.baseUnitPrice || '';
|
||
}
|
||
|
||
if (packagePriceNode) {
|
||
packagePriceNode.dataset.basePackagePrice = button.dataset.basePackagePrice || '';
|
||
}
|
||
|
||
if (packageLabelNode) {
|
||
packageLabelNode.textContent = button.dataset.variantPackageLabel || button.dataset.variantName || 'Фасовка';
|
||
}
|
||
|
||
if (packageLabelNoteNode) {
|
||
packageLabelNoteNode.textContent = button.dataset.variantPackageLabel || button.dataset.variantName || 'Фасовка';
|
||
}
|
||
|
||
if (oldPriceNode) {
|
||
const oldPackagePrice = button.dataset.oldPrice || '';
|
||
oldPriceNode.textContent = oldPackagePrice;
|
||
oldPriceNode.hidden = oldPackagePrice === '';
|
||
}
|
||
|
||
if (oldUnitPriceNode) {
|
||
const oldUnitPrice = Number(button.dataset.oldUnitPrice || 0);
|
||
const baseUnitPrice = Number(button.dataset.baseUnitPrice || 0);
|
||
const hasOldUnitPrice = oldUnitPrice > baseUnitPrice;
|
||
oldUnitPriceNode.textContent = hasOldUnitPrice ? formatRub(oldUnitPrice) : '';
|
||
oldUnitPriceNode.hidden = !hasOldUnitPrice;
|
||
}
|
||
|
||
updateCardPrices(card);
|
||
});
|
||
|
||
updateAllPrices();
|
||
})();
|
||
</script>
|
||
</body>
|
||
</html>
|