доставка в плавающем

This commit is contained in:
Alisa
2026-06-08 10:58:47 +03:00
parent 3a065b34d6
commit 256afcbb80
18 changed files with 1478 additions and 187 deletions
+117 -41
View File
@@ -25,6 +25,7 @@
<label>
Адрес доставки
<input type="text" name="address" placeholder="Например: Москва, ул. Привольная, 13к1">
<small class="cart-address-status" id="delivery-address-status" hidden></small>
</label>
<label>
@@ -35,21 +36,18 @@
<label>
Способ получения
<select name="zone">
<option value="inside">Доставка внутри МКАД</option>
<option value="outside">Доставка за МКАД</option>
<option value="inside_mkad">Доставка внутри МКАД</option>
<option value="outside_mkad">Доставка за МКАД</option>
<option value="pickup">Самовывоз</option>
</select>
</label>
<label class="km-field">
Км от МКАД
<input type="number" name="km" min="0" step="1" value="0">
</label>
<label class="checkbox-label">
<input type="checkbox" name="lift">
Нужен подъем до квартиры/офиса
</label>
<button class="secondary-button calculator-submit" type="button" data-delivery-calc-button>Рассчитать</button>
</form>
<div class="calculator-result" id="delivery-result">
@@ -60,7 +58,9 @@
<div class="info-grid">
<section class="info-card">
<div class="info-card-visual delivery-city"></div>
<figure class="delivery-vehicle-visual delivery-city">
<img src="/assets/img/delivery-van-city.svg" alt="Рефрижератор Рыбсток для доставки внутри МКАД">
</figure>
<h2>Доставка внутри МКАД</h2>
<ul class="clean-list">
<li>Заказы от 5000 руб. - бесплатно до подъезда.</li>
@@ -72,7 +72,9 @@
</section>
<section class="info-card">
<div class="info-card-visual delivery-region"></div>
<figure class="delivery-vehicle-visual delivery-region">
<img src="/assets/img/delivery-van-region.svg" alt="Рефрижератор Рыбсток для доставки за МКАД">
</figure>
<h2>Доставка за МКАД</h2>
<ul class="clean-list">
<li>До 10 км от МКАД бесплатная доставка от 10000 руб.</li>
@@ -113,57 +115,131 @@
</section>
<script>
(() => {
window.addEventListener('load', () => {
const form = document.getElementById('delivery-calculator');
const result = document.getElementById('delivery-result');
const addressStatus = document.getElementById('delivery-address-status');
if (!form || !result) {
return;
}
const formatRub = (value) => new Intl.NumberFormat('ru-RU').format(Math.max(0, Math.round(value))) + ' руб.';
const formatRub = (value) => window.RybStockDelivery?.formatRub
? window.RybStockDelivery.formatRub(value)
: new Intl.NumberFormat('ru-RU').format(Math.max(0, Math.round(value))) + ' руб.';
let resolvedDistance = 0;
let resolvedZone = '';
let addressTimer = null;
let addressRequestId = 0;
const setAddressStatus = (message) => {
if (!addressStatus) {
return;
}
addressStatus.hidden = message === '';
addressStatus.textContent = message;
};
const calculate = () => {
const data = new FormData(form);
const orderSum = Number(data.get('order_sum') || 0);
const zone = String(data.get('zone') || 'inside');
const km = Math.max(0, Number(data.get('km') || 0));
const zone = String(data.get('zone') || 'inside_mkad');
const lift = data.get('lift') === 'on';
const liftPrice = lift ? 390 : 0;
let delivery = 0;
let title = '';
let note = '';
const effectiveZone = resolvedZone === 'outside'
? 'outside_mkad'
: (resolvedZone === 'inside' ? 'inside_mkad' : zone);
const distance = effectiveZone === 'outside_mkad' ? resolvedDistance : 0;
const quote = window.RybStockDelivery?.quote
? window.RybStockDelivery.quote(effectiveZone, orderSum, distance, lift, resolvedZone)
: { label: 'Расчет доставки', note: 'Обновите страницу, чтобы загрузить калькулятор.', total: 0, minimumMessage: '' };
const title = quote.selected ? `${quote.label}: ${formatRub(quote.total)}` : quote.label;
const liftNote = lift && effectiveZone !== 'pickup' ? ` Подъем включен: 390 руб.` : '';
const minimumNote = quote.minimumMessage ? ` ${quote.minimumMessage}` : '';
form.querySelector('.km-field').style.display = zone === 'outside' ? 'grid' : 'none';
result.innerHTML = `<strong>${title}</strong><span>${quote.note}${liftNote}${minimumNote}</span>`;
};
const resolveAddress = () => {
const address = String(new FormData(form).get('address') || '').trim();
const zone = String(new FormData(form).get('zone') || 'inside_mkad');
const requestId = ++addressRequestId;
if (zone === 'pickup') {
delivery = 0;
title = 'Самовывоз: бесплатно';
note = orderSum < 1
? 'Минимальная сумма заказа на самовывоз - 1 руб.'
: 'Самовывоз возможен после подтверждения заказа.';
} else if (zone === 'inside') {
delivery = orderSum >= 5000 ? 0 : 599;
title = delivery === 0 ? 'Доставка внутри МКАД: бесплатно' : 'Доставка внутри МКАД: ' + formatRub(delivery);
note = orderSum < 2000
? 'Минимальная сумма заказа на доставку внутри МКАД - 2000 руб.'
: 'Бесплатная доставка внутри МКАД от 5000 руб.';
} else {
const freeThreshold = km <= 10 ? 10000 : Math.ceil(km) * 1000;
delivery = orderSum >= freeThreshold ? 0 : 199 + km * 60;
title = delivery === 0 ? 'Доставка за МКАД: бесплатно' : 'Доставка за МКАД: ' + formatRub(delivery);
note = 'Порог бесплатной доставки для этого расстояния: ' + formatRub(freeThreshold) + '. Платная доставка: 199 руб. + 60 руб./км.';
if (orderSum < 5000) {
note += ' Минимальная сумма заказа за МКАД - 5000 руб.';
}
resolvedDistance = 0;
resolvedZone = '';
setAddressStatus('');
calculate();
return;
}
const total = delivery + liftPrice;
result.innerHTML = '<strong>' + title + '</strong><span>' + note + (lift ? ' Подъем: 390 руб. Итого с подъемом: ' + formatRub(total) + '.' : '') + '</span>';
if (address.length < 6) {
resolvedDistance = 0;
resolvedZone = '';
setAddressStatus('Введите адрес и выберите вариант из подсказки, чтобы сайт рассчитал доставку автоматически.');
calculate();
return;
}
setAddressStatus('Рассчитываем расстояние по адресу...');
if (!window.RybStockDelivery?.resolveAddress) {
resolvedDistance = 0;
resolvedZone = '';
setAddressStatus('Калькулятор еще загружается. Если расчет не появился, обновите страницу.');
calculate();
return;
}
window.RybStockDelivery.resolveAddress(address)
.then((resolved) => {
if (requestId !== addressRequestId) {
return;
}
resolvedDistance = Number(resolved.distance || 0);
resolvedZone = String(resolved.zone || '');
if (resolvedZone === 'outside') {
form.querySelector('[name="zone"]').value = 'outside_mkad';
} else if (resolvedZone === 'inside') {
form.querySelector('[name="zone"]').value = 'inside_mkad';
}
setAddressStatus(resolved.status || '');
calculate();
})
.catch(() => {
if (requestId !== addressRequestId) {
return;
}
resolvedDistance = 0;
resolvedZone = '';
setAddressStatus('Не удалось автоматически рассчитать адрес. Менеджер уточнит доставку по телефону.');
calculate();
});
};
const scheduleResolveAddress = () => {
window.clearTimeout(addressTimer);
addressTimer = window.setTimeout(resolveAddress, 700);
};
form.addEventListener('input', calculate);
form.addEventListener('change', calculate);
form.addEventListener('input', (event) => {
if (event.target.matches('[name="address"]')) {
scheduleResolveAddress();
}
});
form.addEventListener('change', () => {
resolveAddress();
calculate();
});
form.querySelector('[data-delivery-calc-button]')?.addEventListener('click', () => {
resolveAddress();
calculate();
});
window.RybStockDelivery?.setupAddressSuggestions?.();
resolveAddress();
calculate();
})();
});
</script>