главная сырой слайдер форма запроса цен
This commit is contained in:
+256
-5
@@ -496,7 +496,14 @@ body {
|
|||||||
line-height: 1;
|
line-height: 1;
|
||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
background: var(--brand-red);
|
background: var(--brand-red);
|
||||||
white-space: nowrap;
|
text-align: center;
|
||||||
|
white-space: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.price-mode-button-qr b {
|
||||||
|
max-width: 190px;
|
||||||
|
line-height: 1.1;
|
||||||
|
background: var(--brand-green-2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.price-mode-button-cash {
|
.price-mode-button-cash {
|
||||||
@@ -1817,6 +1824,20 @@ body[data-payment-mode="cash"] .price-tier-popover:hover {
|
|||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.cart-weight-notice {
|
||||||
|
max-width: 980px;
|
||||||
|
border: 1px solid rgba(196, 61, 49, 0.24);
|
||||||
|
border-left: 5px solid var(--brand-red);
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-top: 18px;
|
||||||
|
padding: 14px 16px;
|
||||||
|
color: var(--brand-green);
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 850;
|
||||||
|
line-height: 1.45;
|
||||||
|
background: #fff8f4;
|
||||||
|
}
|
||||||
|
|
||||||
.cart-layout {
|
.cart-layout {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: minmax(0, 1fr) minmax(300px, 0.36fr);
|
grid-template-columns: minmax(0, 1fr) minmax(300px, 0.36fr);
|
||||||
@@ -1825,11 +1846,20 @@ body[data-payment-mode="cash"] .price-tier-popover:hover {
|
|||||||
margin-top: 18px;
|
margin-top: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.cart-layout-checkout {
|
||||||
|
grid-template-columns: minmax(0, 1fr) minmax(320px, 0.38fr);
|
||||||
|
}
|
||||||
|
|
||||||
.cart-items-panel,
|
.cart-items-panel,
|
||||||
.cart-summary {
|
.cart-summary {
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.cart-summary {
|
||||||
|
position: sticky;
|
||||||
|
top: 182px;
|
||||||
|
}
|
||||||
|
|
||||||
.cart-empty {
|
.cart-empty {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
color: var(--muted);
|
color: var(--muted);
|
||||||
@@ -1838,6 +1868,7 @@ body[data-payment-mode="cash"] .price-tier-popover:hover {
|
|||||||
.cart-items {
|
.cart-items {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
|
margin-bottom: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cart-row {
|
.cart-row {
|
||||||
@@ -1966,10 +1997,215 @@ body[data-payment-mode="cash"] .price-tier-popover:hover {
|
|||||||
color: var(--muted);
|
color: var(--muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
.cart-summary-action {
|
.cart-checkout-panel {
|
||||||
|
display: grid;
|
||||||
|
gap: 16px;
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-top: 14px;
|
||||||
|
padding: 18px;
|
||||||
|
background: #fbfcf8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cart-payment-options,
|
||||||
|
.cart-delivery-options {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cart-payment-trust {
|
||||||
|
width: fit-content;
|
||||||
|
border-radius: 999px;
|
||||||
|
margin-bottom: -4px;
|
||||||
|
padding: 7px 12px;
|
||||||
|
color: #ffffff;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 950;
|
||||||
|
letter-spacing: 0.01em;
|
||||||
|
background: linear-gradient(135deg, var(--brand-green), var(--brand-green-2));
|
||||||
|
box-shadow: 0 8px 18px rgba(23, 61, 44, 0.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cart-invoice-details {
|
||||||
|
display: grid;
|
||||||
|
gap: 12px;
|
||||||
|
max-height: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
border: 0 solid transparent;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 0 14px;
|
||||||
|
opacity: 0;
|
||||||
|
background: #f7faf4;
|
||||||
|
transition: max-height 0.28s ease, padding 0.28s ease, opacity 0.2s ease, border-color 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
body[data-payment-mode="invoice"] .cart-invoice-details {
|
||||||
|
max-height: 520px;
|
||||||
|
border-width: 1px;
|
||||||
|
border-color: #dfe8dc;
|
||||||
|
padding: 14px;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cart-invoice-details p {
|
||||||
|
margin: 0;
|
||||||
|
color: var(--muted);
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cart-invoice-details label {
|
||||||
|
display: grid;
|
||||||
|
gap: 7px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 850;
|
||||||
|
color: #394437;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cart-delivery-options label {
|
||||||
|
display: inline-flex;
|
||||||
|
gap: 8px;
|
||||||
|
align-items: center;
|
||||||
|
min-height: 42px;
|
||||||
|
border: 1px solid #cfd8c9;
|
||||||
|
border-radius: 999px;
|
||||||
|
padding: 9px 14px;
|
||||||
|
font-weight: 900;
|
||||||
|
color: var(--brand-green);
|
||||||
|
background: #ffffff;
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
transition: border-color 0.16s ease, background 0.16s ease, color 0.16s ease, transform 0.16s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cart-delivery-options label:hover {
|
||||||
|
border-color: var(--brand-green);
|
||||||
|
background: #f2f7ef;
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cart-delivery-options label:has(input:checked) {
|
||||||
|
color: #ffffff;
|
||||||
|
border-color: var(--brand-green);
|
||||||
|
background: var(--brand-green);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cart-delivery-options input {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cart-minimum-warning {
|
||||||
|
border: 1px solid rgba(196, 61, 49, 0.24);
|
||||||
|
border-radius: 8px;
|
||||||
|
margin: 0;
|
||||||
|
padding: 12px 14px;
|
||||||
|
color: #7c2118;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 850;
|
||||||
|
background: #fff1ee;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cart-delivery-fields,
|
||||||
|
.cart-form-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cart-delivery-fields label,
|
||||||
|
.cart-order-form label {
|
||||||
|
display: grid;
|
||||||
|
gap: 7px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 850;
|
||||||
|
color: #394437;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cart-lift-label {
|
||||||
|
grid-template-columns: auto minmax(0, 1fr);
|
||||||
|
align-items: center;
|
||||||
|
align-self: end;
|
||||||
|
min-height: 44px;
|
||||||
|
border: 1px solid #cfd8c9;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 12px;
|
||||||
|
background: #ffffff;
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cart-lift-label input {
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cart-lift-label:has(input:checked) {
|
||||||
|
border-color: var(--brand-green);
|
||||||
|
background: #eef6e9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cart-final-sum-label {
|
||||||
|
grid-template-columns: auto minmax(0, 1fr);
|
||||||
|
align-items: start;
|
||||||
|
border: 1px solid #dfe8dc;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 12px;
|
||||||
|
background: #f7faf4;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cart-final-sum-label input {
|
||||||
|
width: auto;
|
||||||
|
margin-top: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cart-delivery-fields input,
|
||||||
|
.cart-order-form input,
|
||||||
|
.cart-order-form textarea,
|
||||||
|
.cart-invoice-details textarea,
|
||||||
|
.cart-invoice-details input {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
justify-content: center;
|
border: 1px solid #cfd8c9;
|
||||||
margin-top: 10px;
|
border-radius: 8px;
|
||||||
|
padding: 12px;
|
||||||
|
font: inherit;
|
||||||
|
background: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cart-order-form {
|
||||||
|
display: grid;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cart-confirm-button {
|
||||||
|
width: fit-content;
|
||||||
|
min-width: 220px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cart-form-note {
|
||||||
|
margin: 0;
|
||||||
|
color: var(--muted);
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cart-order-success {
|
||||||
|
border: 1px solid rgba(23, 61, 44, 0.18);
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-top: 14px;
|
||||||
|
padding: 14px;
|
||||||
|
color: var(--brand-green);
|
||||||
|
background: #eef6e9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cart-order-success strong {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
color: var(--brand-green);
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cart-order-success p {
|
||||||
|
margin: 0;
|
||||||
|
color: #394437;
|
||||||
}
|
}
|
||||||
|
|
||||||
.product-description {
|
.product-description {
|
||||||
@@ -3004,6 +3240,10 @@ body[data-payment-mode="invoice"] .invoice-benefit-banner {
|
|||||||
max-height: none;
|
max-height: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.cart-summary {
|
||||||
|
position: static;
|
||||||
|
}
|
||||||
|
|
||||||
.catalog-sidebar {
|
.catalog-sidebar {
|
||||||
position: static;
|
position: static;
|
||||||
max-height: none;
|
max-height: none;
|
||||||
@@ -3168,7 +3408,9 @@ body[data-payment-mode="invoice"] .invoice-benefit-banner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.content-grid,
|
.content-grid,
|
||||||
.calculator-form {
|
.calculator-form,
|
||||||
|
.cart-delivery-fields,
|
||||||
|
.cart-form-grid {
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3235,4 +3477,13 @@ body[data-payment-mode="invoice"] .invoice-benefit-banner {
|
|||||||
grid-column: 2;
|
grid-column: 2;
|
||||||
justify-self: start;
|
justify-self: start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.cart-payment-options,
|
||||||
|
.cart-delivery-options {
|
||||||
|
display: grid;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cart-confirm-button {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+329
-3
@@ -9,6 +9,8 @@ declare(strict_types=1);
|
|||||||
/** @var array<int, array{title: string, url?: string}> $breadcrumbs */
|
/** @var array<int, array{title: string, url?: string}> $breadcrumbs */
|
||||||
/** @var bool $showBackButton */
|
/** @var bool $showBackButton */
|
||||||
$megaCategories = [];
|
$megaCategories = [];
|
||||||
|
$currentPath = parse_url($_SERVER['REQUEST_URI'] ?? '/', PHP_URL_PATH) ?: '/';
|
||||||
|
$isCartPage = $currentPath === '/cart';
|
||||||
$brandLogoSvg = <<<'SVG'
|
$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">
|
<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>
|
<title id="brand-logo-title">Рыбсток</title>
|
||||||
@@ -122,6 +124,7 @@ try {
|
|||||||
|
|
||||||
<?php require base_path('views/partials/mega-category-menu.php'); ?>
|
<?php require base_path('views/partials/mega-category-menu.php'); ?>
|
||||||
|
|
||||||
|
<?php if (!$isCartPage): ?>
|
||||||
<section class="price-mode-bar" aria-label="Система оплаты при получении">
|
<section class="price-mode-bar" aria-label="Система оплаты при получении">
|
||||||
<div class="price-mode-inner">
|
<div class="price-mode-inner">
|
||||||
<span>Выберите систему оплаты при получении:</span>
|
<span>Выберите систему оплаты при получении:</span>
|
||||||
@@ -130,11 +133,15 @@ try {
|
|||||||
<span>Наличными</span>
|
<span>Наличными</span>
|
||||||
<b>Выгодно от 7000р.</b>
|
<b>Выгодно от 7000р.</b>
|
||||||
</button>
|
</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>
|
<button type="button" class="price-mode-button" data-payment-mode="invoice">Расчетный счет</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
<header class="site-utility">
|
<header class="site-utility">
|
||||||
<?php if ($showBackButton): ?>
|
<?php if ($showBackButton): ?>
|
||||||
@@ -261,10 +268,17 @@ try {
|
|||||||
const storageKeys = {
|
const storageKeys = {
|
||||||
paymentMode: 'rybstock_payment_mode',
|
paymentMode: 'rybstock_payment_mode',
|
||||||
cartTotal: 'rybstock_cart_total',
|
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 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 getCartTotal = () => Number(localStorage.getItem(storageKeys.cartTotal) || 0);
|
||||||
const getCartItems = () => {
|
const getCartItems = () => {
|
||||||
try {
|
try {
|
||||||
@@ -294,7 +308,7 @@ try {
|
|||||||
const total = getCartTotal();
|
const total = getCartTotal();
|
||||||
|
|
||||||
if (payment === 'invoice') {
|
if (payment === 'invoice') {
|
||||||
return { multiplier: 1.08, fixedDiscount: 0, label: 'Оплата по расчетному счету: +8%' };
|
return { multiplier: 1.08, fixedDiscount: 0, label: 'Расчетный счет: счет день в день' };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (payment === 'qr') {
|
if (payment === 'qr') {
|
||||||
@@ -323,6 +337,115 @@ try {
|
|||||||
return Math.max(0, subtotal - Number(mode.fixedDiscount || 0));
|
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) => ({
|
const tierValues = (base) => ({
|
||||||
base: base,
|
base: base,
|
||||||
cash20: base * 0.95,
|
cash20: base * 0.95,
|
||||||
@@ -412,10 +535,20 @@ try {
|
|||||||
const modeNode = cartPage.querySelector('[data-cart-current-mode]');
|
const modeNode = cartPage.querySelector('[data-cart-current-mode]');
|
||||||
const savingRow = cartPage.querySelector('[data-cart-saving-row]');
|
const savingRow = cartPage.querySelector('[data-cart-saving-row]');
|
||||||
const savingNode = cartPage.querySelector('[data-cart-saving-total]');
|
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 items = getCartItems();
|
||||||
const baseTotal = cartBaseTotal(items);
|
const baseTotal = cartBaseTotal(items);
|
||||||
const currentTotal = cartCurrentTotal(items);
|
const currentTotal = cartCurrentTotal(items);
|
||||||
const savingTotal = Math.max(0, baseTotal - currentTotal);
|
const savingTotal = Math.max(0, baseTotal - currentTotal);
|
||||||
|
const delivery = deliveryCalculation(items);
|
||||||
|
|
||||||
if (emptyNode) {
|
if (emptyNode) {
|
||||||
emptyNode.hidden = items.length !== 0;
|
emptyNode.hidden = items.length !== 0;
|
||||||
@@ -465,6 +598,47 @@ try {
|
|||||||
if (savingNode) {
|
if (savingNode) {
|
||||||
savingNode.textContent = formatRub(savingTotal);
|
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 = () => {
|
const updateModeButtons = () => {
|
||||||
@@ -547,6 +721,158 @@ try {
|
|||||||
window.RybStockPricing.setPaymentMode(modeButton.dataset.paymentMode || 'cash');
|
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) => {
|
document.addEventListener('click', (event) => {
|
||||||
const quantityButton = event.target.closest('[data-quantity-minus], [data-quantity-plus]');
|
const quantityButton = event.target.closest('[data-quantity-minus], [data-quantity-plus]');
|
||||||
|
|
||||||
|
|||||||
+121
-7
@@ -2,10 +2,13 @@
|
|||||||
<div class="cart-hero">
|
<div class="cart-hero">
|
||||||
<p class="eyebrow">Ваш заказ</p>
|
<p class="eyebrow">Ваш заказ</p>
|
||||||
<h1>Корзина</h1>
|
<h1>Корзина</h1>
|
||||||
<p>Цены пересчитываются автоматически: наличными от 20 000р. действует -5%, от 50 000р. -7%, QR-код показывает базовую цену, расчетный счет показывает +8%.</p>
|
<p>Проверьте фасовки, выберите способ оплаты и получение. Сайт сразу пересчитает выгоду, доставку и итоговую сумму.</p>
|
||||||
|
<div class="cart-weight-notice">
|
||||||
|
Весовые позиции пересчитываются при сборке по фактическому весу. Если Вам нужна итоговая сумма до получения товара, отметьте это в форме заказа: после сборки менеджер перезвонит и сообщит сумму.
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="cart-layout">
|
<div class="cart-layout cart-layout-checkout">
|
||||||
<section class="cart-items-panel">
|
<section class="cart-items-panel">
|
||||||
<div class="section-heading">
|
<div class="section-heading">
|
||||||
<div>
|
<div>
|
||||||
@@ -17,6 +20,109 @@
|
|||||||
|
|
||||||
<p class="cart-empty" data-cart-empty>Корзина пока пустая. Перейдите в каталог и добавьте нужные фасовки.</p>
|
<p class="cart-empty" data-cart-empty>Корзина пока пустая. Перейдите в каталог и добавьте нужные фасовки.</p>
|
||||||
<div class="cart-items" data-cart-items></div>
|
<div class="cart-items" data-cart-items></div>
|
||||||
|
|
||||||
|
<section class="cart-checkout-panel">
|
||||||
|
<div class="cart-payment-trust">Оплата только при получении</div>
|
||||||
|
<div class="section-heading">
|
||||||
|
<div>
|
||||||
|
<p class="eyebrow">Оплата</p>
|
||||||
|
<h2>Выберите способ оплаты</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cart-payment-options" role="group" aria-label="Способ оплаты">
|
||||||
|
<button type="button" class="price-mode-button price-mode-button-cash" data-payment-mode="cash">
|
||||||
|
<span>Наличными</span>
|
||||||
|
<b>Выгодно от 7000р.</b>
|
||||||
|
</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 class="cart-invoice-details" data-invoice-details>
|
||||||
|
<p>Для счета можно указать реквизиты текстом или прикрепить файл. Счет подготовим день в день после подтверждения заказа.</p>
|
||||||
|
<label>
|
||||||
|
<span>Реквизиты организации</span>
|
||||||
|
<textarea name="invoice_requisites" data-order-invoice-requisites rows="4" placeholder="ИНН, название организации, email для счета"></textarea>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<span>Файл с реквизитами</span>
|
||||||
|
<input type="file" name="invoice_files[]" data-order-invoice-file accept=".pdf,.doc,.docx,.xls,.xlsx,.jpg,.jpeg,.png" multiple>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="cart-checkout-panel">
|
||||||
|
<div class="section-heading">
|
||||||
|
<div>
|
||||||
|
<p class="eyebrow">Получение</p>
|
||||||
|
<h2>Доставка или самовывоз</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="cart-delivery-options" role="radiogroup" aria-label="Способ получения">
|
||||||
|
<label>
|
||||||
|
<input type="radio" name="cart_delivery_type" value="pickup" data-cart-delivery-type>
|
||||||
|
<span>Самовывоз</span>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<input type="radio" name="cart_delivery_type" value="inside_mkad" data-cart-delivery-type>
|
||||||
|
<span>Доставка внутри МКАД</span>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<input type="radio" name="cart_delivery_type" value="outside_mkad" data-cart-delivery-type>
|
||||||
|
<span>Доставка за МКАД</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<p class="cart-minimum-warning" data-cart-minimum-warning hidden></p>
|
||||||
|
|
||||||
|
<div class="cart-delivery-fields">
|
||||||
|
<label>
|
||||||
|
<span>Адрес доставки</span>
|
||||||
|
<input type="text" data-cart-address placeholder="Например: Москва, ул. Привольная, 13к1">
|
||||||
|
</label>
|
||||||
|
<label class="cart-lift-label" data-lift-field hidden>
|
||||||
|
<input type="checkbox" data-cart-lift>
|
||||||
|
<span>Нужен подъем до квартиры/офиса +390 руб.</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="cart-checkout-panel">
|
||||||
|
<div class="section-heading">
|
||||||
|
<div>
|
||||||
|
<p class="eyebrow">Контакты</p>
|
||||||
|
<h2>Куда перезвонить</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<form class="cart-order-form" data-cart-order-form>
|
||||||
|
<div class="cart-form-grid">
|
||||||
|
<label>
|
||||||
|
<span>Имя *</span>
|
||||||
|
<input type="text" name="customer_name" data-order-name required>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<span>Телефон *</span>
|
||||||
|
<input type="tel" name="phone" data-order-phone required placeholder="+7">
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<span>Email (необязательно)</span>
|
||||||
|
<input type="email" name="email" data-order-email placeholder="Если хотите получить копию заказа">
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<label class="cart-final-sum-label">
|
||||||
|
<input type="checkbox" name="final_sum_needed" data-order-final-sum-needed>
|
||||||
|
<span>Нужна итоговая сумма до получения товара. После сборки менеджер перезвонит и сообщит сумму.</span>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<span>Комментарий</span>
|
||||||
|
<textarea name="comment" data-order-comment rows="4" placeholder="Например: буду дома после 19.00 или нужен номер машины для заказа пропуска."></textarea>
|
||||||
|
</label>
|
||||||
|
<button class="primary-button cart-confirm-button" type="submit">Подтвердить заказ</button>
|
||||||
|
<p class="cart-form-note">На сайте Вы оформляете предзаказ. Мы перезвоним Вам и утвердим наличие, оплата производится при получении товара.</p>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<aside class="cart-summary">
|
<aside class="cart-summary">
|
||||||
@@ -24,7 +130,7 @@
|
|||||||
<h2>Итого</h2>
|
<h2>Итого</h2>
|
||||||
<dl>
|
<dl>
|
||||||
<div>
|
<div>
|
||||||
<dt>Базовая сумма</dt>
|
<dt>Базовая сумма товаров</dt>
|
||||||
<dd data-cart-base-total>0 руб.</dd>
|
<dd data-cart-base-total>0 руб.</dd>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@@ -35,13 +141,21 @@
|
|||||||
<dt>Ваша выгода</dt>
|
<dt>Ваша выгода</dt>
|
||||||
<dd data-cart-saving-total>0 руб.</dd>
|
<dd data-cart-saving-total>0 руб.</dd>
|
||||||
</div>
|
</div>
|
||||||
<div class="cart-summary-total">
|
<div>
|
||||||
<dt>Сумма к расчету</dt>
|
<dt>Товары с учетом оплаты</dt>
|
||||||
<dd data-cart-current-total>0 руб.</dd>
|
<dd data-cart-current-total>0 руб.</dd>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<dt>Доставка</dt>
|
||||||
|
<dd data-cart-delivery-total>Выберите получение</dd>
|
||||||
|
</div>
|
||||||
|
<div class="cart-summary-total">
|
||||||
|
<dt>К оплате при получении</dt>
|
||||||
|
<dd data-cart-grand-total>0 руб.</dd>
|
||||||
|
</div>
|
||||||
</dl>
|
</dl>
|
||||||
<p>Окончательная сумма весовых товаров подтверждается менеджером после проверки фактического веса и наличия.</p>
|
<p data-cart-delivery-note>Выберите способ получения, чтобы увидеть расчет доставки.</p>
|
||||||
<a class="primary-button cart-summary-action" href="/contacts">Связаться по заказу</a>
|
<div class="cart-order-success" data-cart-order-success hidden></div>
|
||||||
</aside>
|
</aside>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
Reference in New Issue
Block a user