главная сырой слайдер форма запроса цен
This commit is contained in:
+329
-3
@@ -9,6 +9,8 @@ declare(strict_types=1);
|
||||
/** @var array<int, array{title: string, url?: string}> $breadcrumbs */
|
||||
/** @var bool $showBackButton */
|
||||
$megaCategories = [];
|
||||
$currentPath = parse_url($_SERVER['REQUEST_URI'] ?? '/', PHP_URL_PATH) ?: '/';
|
||||
$isCartPage = $currentPath === '/cart';
|
||||
$brandLogoSvg = <<<'SVG'
|
||||
<svg class="brand-logo-svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 650 220" role="img" aria-labelledby="brand-logo-title brand-logo-desc">
|
||||
<title id="brand-logo-title">Рыбсток</title>
|
||||
@@ -122,6 +124,7 @@ try {
|
||||
|
||||
<?php require base_path('views/partials/mega-category-menu.php'); ?>
|
||||
|
||||
<?php if (!$isCartPage): ?>
|
||||
<section class="price-mode-bar" aria-label="Система оплаты при получении">
|
||||
<div class="price-mode-inner">
|
||||
<span>Выберите систему оплаты при получении:</span>
|
||||
@@ -130,11 +133,15 @@ try {
|
||||
<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 price-mode-button-qr" data-payment-mode="qr">
|
||||
<span>QR-код</span>
|
||||
<b>Без комиссии даже с кредитки</b>
|
||||
</button>
|
||||
<button type="button" class="price-mode-button" data-payment-mode="invoice">Расчетный счет</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<?php endif; ?>
|
||||
|
||||
<header class="site-utility">
|
||||
<?php if ($showBackButton): ?>
|
||||
@@ -261,10 +268,17 @@ try {
|
||||
const storageKeys = {
|
||||
paymentMode: 'rybstock_payment_mode',
|
||||
cartTotal: 'rybstock_cart_total',
|
||||
cartItems: 'rybstock_cart_items'
|
||||
cartItems: 'rybstock_cart_items',
|
||||
deliveryType: 'rybstock_delivery_type',
|
||||
deliveryDistance: 'rybstock_delivery_distance',
|
||||
deliveryLift: 'rybstock_delivery_lift',
|
||||
deliveryAddress: 'rybstock_delivery_address'
|
||||
};
|
||||
|
||||
const getPaymentMode = () => localStorage.getItem(storageKeys.paymentMode) || 'cash';
|
||||
const getDeliveryType = () => localStorage.getItem(storageKeys.deliveryType) || '';
|
||||
const getDeliveryDistance = () => Math.max(0, Number(localStorage.getItem(storageKeys.deliveryDistance) || 0));
|
||||
const getDeliveryLift = () => localStorage.getItem(storageKeys.deliveryLift) === '1';
|
||||
const getCartTotal = () => Number(localStorage.getItem(storageKeys.cartTotal) || 0);
|
||||
const getCartItems = () => {
|
||||
try {
|
||||
@@ -294,7 +308,7 @@ try {
|
||||
const total = getCartTotal();
|
||||
|
||||
if (payment === 'invoice') {
|
||||
return { multiplier: 1.08, fixedDiscount: 0, label: 'Оплата по расчетному счету: +8%' };
|
||||
return { multiplier: 1.08, fixedDiscount: 0, label: 'Расчетный счет: счет день в день' };
|
||||
}
|
||||
|
||||
if (payment === 'qr') {
|
||||
@@ -323,6 +337,115 @@ try {
|
||||
return Math.max(0, subtotal - Number(mode.fixedDiscount || 0));
|
||||
};
|
||||
|
||||
const deliveryLabels = {
|
||||
pickup: 'самовывоз',
|
||||
inside_mkad: 'доставку внутри МКАД',
|
||||
outside_mkad: 'доставку за МКАД'
|
||||
};
|
||||
|
||||
const deliveryMinimums = {
|
||||
pickup: 1,
|
||||
inside_mkad: 2000,
|
||||
outside_mkad: 5000
|
||||
};
|
||||
|
||||
const deliveryMinimumMessage = (type, amount) => {
|
||||
const minimum = deliveryMinimums[type] || 0;
|
||||
const missing = Math.max(0, minimum - amount);
|
||||
|
||||
if (missing <= 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return `Уважаемый клиент, Вы выбрали ${deliveryLabels[type] || 'получение'}, минимальная сумма - ${formatRub(minimum)}, добавьте пожалуйста товары на сумму ${formatRub(missing)}.`;
|
||||
};
|
||||
|
||||
const deliveryCalculation = (items = getCartItems()) => {
|
||||
const type = getDeliveryType();
|
||||
const amount = cartCurrentTotal(items);
|
||||
const lift = getDeliveryLift() && type !== 'pickup' ? 390 : 0;
|
||||
const distance = getDeliveryDistance();
|
||||
const minimum = deliveryMinimums[type] || 0;
|
||||
const minimumOk = type ? amount >= minimum : false;
|
||||
const minimumMessage = type ? deliveryMinimumMessage(type, amount) : '';
|
||||
|
||||
if (!type) {
|
||||
return {
|
||||
selected: false,
|
||||
minimumOk: false,
|
||||
minimumMessage: '',
|
||||
price: 0,
|
||||
lift,
|
||||
total: 0,
|
||||
label: 'Выберите получение',
|
||||
note: 'Выберите самовывоз, доставку внутри МКАД или доставку за МКАД.'
|
||||
};
|
||||
}
|
||||
|
||||
if (type === 'pickup') {
|
||||
return {
|
||||
selected: true,
|
||||
minimumOk,
|
||||
minimumMessage,
|
||||
price: 0,
|
||||
lift: 0,
|
||||
total: 0,
|
||||
label: 'Самовывоз бесплатно',
|
||||
note: 'Самовывоз осуществляется после оформления заказа на сайте и подтверждения заказа по телефону.'
|
||||
};
|
||||
}
|
||||
|
||||
if (type === 'inside_mkad') {
|
||||
const free = amount >= 5000;
|
||||
const price = free ? 0 : 599;
|
||||
|
||||
return {
|
||||
selected: true,
|
||||
minimumOk,
|
||||
minimumMessage,
|
||||
price,
|
||||
lift,
|
||||
total: price + lift,
|
||||
label: free ? 'Бесплатно внутри МКАД' : 'Доставка внутри МКАД',
|
||||
note: free
|
||||
? 'Заказ от 5000 руб. доставим внутри МКАД бесплатно до подъезда. При заказе от 2000 до 5000 руб. доставка внутри МКАД стоит 599 руб.'
|
||||
: 'Доставка внутри МКАД доступна от 2000 руб. При заказе от 2000 до 5000 руб. доставка стоит 599 руб., от 5000 руб. - бесплатно до подъезда.'
|
||||
};
|
||||
}
|
||||
|
||||
if (type === 'outside_mkad' && distance <= 0) {
|
||||
return {
|
||||
selected: true,
|
||||
minimumOk,
|
||||
minimumMessage,
|
||||
price: 0,
|
||||
lift,
|
||||
total: lift,
|
||||
label: 'Доставка за МКАД',
|
||||
note: 'Доставка за МКАД доступна от 5000 руб. До 10 км от МКАД бесплатная доставка от 10000 руб.; дальше минимальная сумма для бесплатной доставки считается как 1000 руб. за каждый км от МКАД. Если заказ не проходит на бесплатную доставку, расчет: 199 руб. + 60 руб. за км.'
|
||||
};
|
||||
}
|
||||
|
||||
const freeThreshold = distance <= 10 ? 10000 : distance * 1000;
|
||||
const free = amount >= freeThreshold;
|
||||
const price = free ? 0 : Math.floor(199 + distance * 60);
|
||||
|
||||
return {
|
||||
selected: true,
|
||||
minimumOk,
|
||||
minimumMessage,
|
||||
price,
|
||||
lift,
|
||||
total: price + lift,
|
||||
label: free ? 'Бесплатно за МКАД' : 'Доставка за МКАД',
|
||||
note: distance > 0
|
||||
? (free
|
||||
? `Заказ проходит на бесплатную доставку: расстояние ${distance} км от МКАД.`
|
||||
: `Расчет доставки: 199 руб. + ${distance} км × 60 руб. Минимум для бесплатной доставки: ${formatRub(freeThreshold)}.`)
|
||||
: 'Доставка за МКАД доступна от 5000 руб. До 10 км от МКАД бесплатная доставка от 10000 руб.; дальше минимальная сумма для бесплатной доставки считается как 1000 руб. за каждый км от МКАД. Если заказ не проходит на бесплатную доставку, расчет: 199 руб. + 60 руб. за км.'
|
||||
};
|
||||
};
|
||||
|
||||
const tierValues = (base) => ({
|
||||
base: base,
|
||||
cash20: base * 0.95,
|
||||
@@ -412,10 +535,20 @@ try {
|
||||
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 deliveryTotalNode = cartPage.querySelector('[data-cart-delivery-total]');
|
||||
const deliveryNoteNode = cartPage.querySelector('[data-cart-delivery-note]');
|
||||
const minimumWarningNode = cartPage.querySelector('[data-cart-minimum-warning]');
|
||||
const grandTotalNode = cartPage.querySelector('[data-cart-grand-total]');
|
||||
const outsideDistanceField = cartPage.querySelector('[data-outside-distance-field]');
|
||||
const liftField = cartPage.querySelector('[data-lift-field]');
|
||||
const addressInput = cartPage.querySelector('[data-cart-address]');
|
||||
const distanceInput = cartPage.querySelector('[data-cart-distance]');
|
||||
const liftInput = cartPage.querySelector('[data-cart-lift]');
|
||||
const items = getCartItems();
|
||||
const baseTotal = cartBaseTotal(items);
|
||||
const currentTotal = cartCurrentTotal(items);
|
||||
const savingTotal = Math.max(0, baseTotal - currentTotal);
|
||||
const delivery = deliveryCalculation(items);
|
||||
|
||||
if (emptyNode) {
|
||||
emptyNode.hidden = items.length !== 0;
|
||||
@@ -465,6 +598,47 @@ try {
|
||||
if (savingNode) {
|
||||
savingNode.textContent = formatRub(savingTotal);
|
||||
}
|
||||
|
||||
cartPage.querySelectorAll('[data-cart-delivery-type]').forEach((input) => {
|
||||
input.checked = input.value === getDeliveryType();
|
||||
});
|
||||
|
||||
if (outsideDistanceField) {
|
||||
outsideDistanceField.hidden = getDeliveryType() !== 'outside_mkad';
|
||||
}
|
||||
|
||||
if (liftField) {
|
||||
liftField.hidden = !['inside_mkad', 'outside_mkad'].includes(getDeliveryType());
|
||||
}
|
||||
|
||||
if (addressInput && document.activeElement !== addressInput) {
|
||||
addressInput.value = localStorage.getItem(storageKeys.deliveryAddress) || '';
|
||||
}
|
||||
|
||||
if (distanceInput && document.activeElement !== distanceInput) {
|
||||
distanceInput.value = getDeliveryDistance() > 0 ? String(getDeliveryDistance()) : '';
|
||||
}
|
||||
|
||||
if (liftInput) {
|
||||
liftInput.checked = getDeliveryLift();
|
||||
}
|
||||
|
||||
if (deliveryTotalNode) {
|
||||
deliveryTotalNode.textContent = delivery.selected ? formatRub(delivery.total) : delivery.label;
|
||||
}
|
||||
|
||||
if (deliveryNoteNode) {
|
||||
deliveryNoteNode.textContent = delivery.note;
|
||||
}
|
||||
|
||||
if (minimumWarningNode) {
|
||||
minimumWarningNode.hidden = !delivery.minimumMessage;
|
||||
minimumWarningNode.textContent = delivery.minimumMessage || '';
|
||||
}
|
||||
|
||||
if (grandTotalNode) {
|
||||
grandTotalNode.textContent = formatRub(currentTotal + delivery.total);
|
||||
}
|
||||
};
|
||||
|
||||
const updateModeButtons = () => {
|
||||
@@ -547,6 +721,158 @@ try {
|
||||
window.RybStockPricing.setPaymentMode(modeButton.dataset.paymentMode || 'cash');
|
||||
});
|
||||
|
||||
document.addEventListener('click', (event) => {
|
||||
const deliveryLabel = event.target.closest('.cart-delivery-options label');
|
||||
|
||||
if (deliveryLabel) {
|
||||
const input = deliveryLabel.querySelector('[data-cart-delivery-type]');
|
||||
|
||||
if (input && !input.checked) {
|
||||
event.preventDefault();
|
||||
input.checked = true;
|
||||
input.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener('click', (event) => {
|
||||
const liftLabel = event.target.closest('.cart-lift-label');
|
||||
|
||||
if (!liftLabel || event.target.closest('[data-cart-lift]')) {
|
||||
return;
|
||||
}
|
||||
|
||||
const input = liftLabel.querySelector('[data-cart-lift]');
|
||||
|
||||
if (input) {
|
||||
event.preventDefault();
|
||||
input.checked = !input.checked;
|
||||
input.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener('change', (event) => {
|
||||
const deliveryType = event.target.closest('[data-cart-delivery-type]');
|
||||
|
||||
if (deliveryType) {
|
||||
localStorage.setItem(storageKeys.deliveryType, deliveryType.value);
|
||||
localStorage.setItem(storageKeys.deliveryDistance, '0');
|
||||
|
||||
if (deliveryType.value === 'pickup') {
|
||||
localStorage.setItem(storageKeys.deliveryLift, '0');
|
||||
}
|
||||
|
||||
updateAllPrices();
|
||||
return;
|
||||
}
|
||||
|
||||
const liftInput = event.target.closest('[data-cart-lift]');
|
||||
|
||||
if (liftInput) {
|
||||
localStorage.setItem(storageKeys.deliveryLift, liftInput.checked ? '1' : '0');
|
||||
updateAllPrices();
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener('input', (event) => {
|
||||
const distanceInput = event.target.closest('[data-cart-distance]');
|
||||
|
||||
if (distanceInput) {
|
||||
localStorage.setItem(storageKeys.deliveryDistance, String(Math.max(0, Number(distanceInput.value || 0))));
|
||||
updateAllPrices();
|
||||
return;
|
||||
}
|
||||
|
||||
const addressInput = event.target.closest('[data-cart-address]');
|
||||
|
||||
if (addressInput) {
|
||||
localStorage.setItem(storageKeys.deliveryAddress, addressInput.value);
|
||||
localStorage.setItem(storageKeys.deliveryDistance, '0');
|
||||
updateAllPrices();
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener('submit', (event) => {
|
||||
const form = event.target.closest('[data-cart-order-form]');
|
||||
|
||||
if (!form) {
|
||||
return;
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
const cartPage = form.closest('[data-cart-page]');
|
||||
const successNode = cartPage?.querySelector('[data-cart-order-success]');
|
||||
const items = getCartItems();
|
||||
const delivery = deliveryCalculation(items);
|
||||
const name = form.querySelector('[data-order-name]')?.value.trim() || '';
|
||||
const phone = form.querySelector('[data-order-phone]')?.value.trim() || '';
|
||||
const email = form.querySelector('[data-order-email]')?.value.trim() || '';
|
||||
const comment = form.querySelector('[data-order-comment]')?.value.trim() || '';
|
||||
const finalSumNeeded = form.querySelector('[data-order-final-sum-needed]')?.checked || false;
|
||||
const invoiceRequisites = form.closest('[data-cart-page]')?.querySelector('[data-order-invoice-requisites]')?.value.trim() || '';
|
||||
const invoiceFiles = [...(form.closest('[data-cart-page]')?.querySelector('[data-order-invoice-file]')?.files || [])].map((file) => file.name);
|
||||
|
||||
if (items.length === 0) {
|
||||
window.alert('Добавьте товары в корзину.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!getDeliveryType()) {
|
||||
window.alert('Выберите самовывоз, доставку внутри МКАД или доставку за МКАД.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!delivery.minimumOk) {
|
||||
window.alert(delivery.minimumMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!name || !phone) {
|
||||
window.alert('Укажите имя и телефон.');
|
||||
return;
|
||||
}
|
||||
|
||||
const orderNumber = 'RS-' + new Date().toISOString().replace(/\D/g, '').slice(0, 14);
|
||||
const productsTotal = cartCurrentTotal(items);
|
||||
const grandTotal = productsTotal + delivery.total;
|
||||
const order = {
|
||||
orderNumber,
|
||||
createdAt: new Date().toISOString(),
|
||||
name,
|
||||
phone,
|
||||
email,
|
||||
comment,
|
||||
finalSumNeeded,
|
||||
invoiceRequisites,
|
||||
invoiceFiles,
|
||||
paymentMode: getPaymentMode(),
|
||||
deliveryType: getDeliveryType(),
|
||||
address: localStorage.getItem(storageKeys.deliveryAddress) || '',
|
||||
distance: getDeliveryDistance(),
|
||||
lift: getDeliveryLift(),
|
||||
items,
|
||||
productsTotal,
|
||||
deliveryTotal: delivery.total,
|
||||
grandTotal
|
||||
};
|
||||
|
||||
localStorage.setItem('rybstock_last_order', JSON.stringify(order));
|
||||
|
||||
if (successNode) {
|
||||
successNode.hidden = false;
|
||||
successNode.innerHTML = `
|
||||
<strong>Спасибо за Ваш заказ. Заказ ${escapeHtml(orderNumber)} принят в обработку.</strong>
|
||||
<p>Спасибо, что оформили заказ на сайте Рыбсток. Мы благодарим Вас за доверие.</p>
|
||||
<p>Доставка и самовывоз товара происходят только после подтверждения заказа по телефону. Сумма к оплате при получении: <b>${formatRub(grandTotal)}</b>.</p>
|
||||
<p>Если заказ оформлен в будний день до 14.00, мы перезвоним Вам сегодня. Если заказ оформлен после 14.00, мы свяжемся на следующий рабочий день с 10.00 до 14.00.</p>
|
||||
<p>Суббота и воскресенье - выходные. Заказы, оформленные в пятницу после 14.00, автоматически переносятся на понедельник.</p>
|
||||
<p>Если у Вас срочный вопрос, свяжитесь с нами по телефону <a href="tel:+79777363363">+7-977-736-33-63</a>.</p>
|
||||
`;
|
||||
successNode.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener('click', (event) => {
|
||||
const quantityButton = event.target.closest('[data-quantity-minus], [data-quantity-plus]');
|
||||
|
||||
|
||||
Reference in New Issue
Block a user