2548 lines
107 KiB
JavaScript
2548 lines
107 KiB
JavaScript
"use strict";
|
||
const host = 'https://local.hvatilo.ru:8055';
|
||
|
||
// Returns a function, that, when invoked, will only be triggered at most once
|
||
// during a given window of time. Normally, the throttled function will run
|
||
// as much as it can, without ever going more than once per `wait` duration;
|
||
// but if you'd like to disable the execution on the leading edge, pass
|
||
// `{leading: false}`. To disable execution on the trailing edge, ditto.
|
||
function throttle(func, wait, options) {
|
||
var context, args, result;
|
||
var timeout = null;
|
||
var previous = 0;
|
||
if (!options) options = {};
|
||
var later = function() {
|
||
previous = options.leading === false ? 0 : Date.now();
|
||
timeout = null;
|
||
result = func.apply(context, args);
|
||
if (!timeout) context = args = null;
|
||
};
|
||
return function() {
|
||
var now = Date.now();
|
||
if (!previous && options.leading === false) previous = now;
|
||
var remaining = wait - (now - previous);
|
||
context = this;
|
||
args = arguments;
|
||
if (remaining <= 0 || remaining > wait) {
|
||
if (timeout) {
|
||
clearTimeout(timeout);
|
||
timeout = null;
|
||
}
|
||
previous = now;
|
||
result = func.apply(context, args);
|
||
if (!timeout) context = args = null;
|
||
} else if (!timeout && options.trailing !== false) {
|
||
timeout = setTimeout(later, remaining);
|
||
}
|
||
return result;
|
||
};
|
||
}
|
||
|
||
function refreshToken() {
|
||
return fetch(host + '/api/guest/refresh_cookie', {method: 'POST', credentials: 'include'})
|
||
.then(response => {
|
||
if (response.status === 400) {
|
||
return fetch(host + '/api/guest/clear_cookie', {method: 'POST', credentials: 'include'})
|
||
.then(async (d) => {
|
||
await new Promise(resolve => setTimeout(resolve, 100));
|
||
return initToken();
|
||
});
|
||
}
|
||
return response.json();
|
||
});
|
||
}
|
||
function initToken() {
|
||
return fetch(host + '/api/guest/init_cookie?utm_source=hvatilo_promo', {method: 'POST', credentials: 'include'}).then(response => {
|
||
return response.json();
|
||
});
|
||
}
|
||
|
||
const requestWithRefresh = async function(url, options) {
|
||
return fetch(url, {...options, credentials: 'include'})
|
||
.then(async response => response.json())
|
||
.then(async data => {
|
||
if (data.error_message === 'need_refresh') {
|
||
return refreshToken()
|
||
.then((r) => {
|
||
console.log('url', url);
|
||
return fetch(url, {...options, credentials: 'include'}).then(response => response.json());
|
||
});
|
||
}
|
||
|
||
return data;
|
||
})
|
||
}
|
||
|
||
const replaceProduct = (async function(product_name) {
|
||
return requestWithRefresh(host + '/api/promo/replace_item', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json'
|
||
},
|
||
body: JSON.stringify({product_name})
|
||
})
|
||
.then(async () => {
|
||
updateCart();
|
||
})
|
||
})
|
||
const deleteProduct = (async function(product_name) {
|
||
return requestWithRefresh(host + '/api/promo/delete_item', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json'
|
||
},
|
||
body: JSON.stringify({product_name})
|
||
})
|
||
})
|
||
const updateCart = throttle(async function() {
|
||
document.getElementById('summary-loader').classList.remove('hidden');
|
||
document.getElementById('summary-details').classList.add('hidden');
|
||
return requestWithRefresh(host + '/api/promo/get_updates', {headers: {
|
||
'Content-Type': 'application/json'
|
||
}}).then(d => {
|
||
if (d.status !== 'complete') {
|
||
initialData_g.excess = d.payload.excess;
|
||
initialData_g.precision = d.payload.precision;
|
||
if (d.status === 'clear') {
|
||
allProducts = [];
|
||
visibleProducts = [];
|
||
|
||
renderProducts();
|
||
|
||
allProducts = d.payload.chunk;
|
||
visibleProducts = d.payload.chunk;
|
||
}
|
||
if (d.status === 'data') {
|
||
d.payload.chunk.forEach(addedProduct => {
|
||
let idx = allProducts.findIndex(p => p.name === addedProduct.name)
|
||
if (idx === -1) {
|
||
allProducts.push({...addedProduct, image: addedProduct.image?.replace('{SIZE}', '65,fit')});
|
||
if (visibleProducts.length === allProducts.length - 1) {
|
||
visibleProducts = allProducts;
|
||
}
|
||
} else {
|
||
allProducts[idx].n += addedProduct.n;
|
||
if (idx < visibleProducts.length) {
|
||
visibleProducts[idx] = allProducts[idx];
|
||
}
|
||
}
|
||
})
|
||
}
|
||
if (d.status !== 'waiting') {
|
||
renderProducts();
|
||
}
|
||
updateCart();
|
||
} else {
|
||
document.getElementsByClassName('cart-footer')[0].classList.add('visible');
|
||
document.getElementById('summary-loader').classList.add('hidden');
|
||
document.getElementById('summary-details').classList.remove('hidden');
|
||
}
|
||
})
|
||
.catch(() => {
|
||
updateCart();
|
||
})
|
||
}, 3000);
|
||
|
||
const setOption = (key, value) => {
|
||
return requestWithRefresh(host + '/api/promo/set_option', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json'
|
||
},
|
||
body: JSON.stringify({[key]: value})
|
||
})
|
||
.then(async d => {
|
||
wholeRender(await loadInitData());
|
||
updateCart();
|
||
|
||
return d;
|
||
})
|
||
.catch(() => {
|
||
console.log('start catch')
|
||
return new Promise((resolve, reject) => {
|
||
|
||
setTimeout(() => {
|
||
console.log('end catch')
|
||
reject('end catch')
|
||
}, 1000);
|
||
})
|
||
})
|
||
}
|
||
const mockData = {
|
||
"existing": 5432,
|
||
"available_groups": [
|
||
"Приправы",
|
||
"Овощи",
|
||
"Напитки",
|
||
"Сыр",
|
||
"Птица в лотках",
|
||
"Сладости",
|
||
"Подсластители",
|
||
"Кисломолочные",
|
||
"Масло для готовки",
|
||
"Ягоды",
|
||
"Соусы",
|
||
"Для готовки",
|
||
"Горячие напитки",
|
||
"Засоленные",
|
||
"Морепродукты",
|
||
"Кисломолочное",
|
||
"Кисломолочные напитки",
|
||
"Алкоголь",
|
||
"Хлебцы",
|
||
"Сладкое-сладкое",
|
||
"Капуста",
|
||
"Детское питание",
|
||
"Овощи для готовки",
|
||
"Гарнир",
|
||
"Хлеб",
|
||
"Консервы",
|
||
"Суп",
|
||
"Острое",
|
||
"Вермишель",
|
||
"Рыба",
|
||
"Сливки",
|
||
"Грибы",
|
||
"Салат",
|
||
"Субпродукты",
|
||
"Картофель",
|
||
"Молочные",
|
||
"Морковь",
|
||
"Жевательная резинка",
|
||
"Фрукты",
|
||
"Зелень",
|
||
"Специальное питание",
|
||
"Яйца"
|
||
],
|
||
"initial_groups": [
|
||
"Овощи",
|
||
"Овощи для готовки",
|
||
"Молочные",
|
||
"Птица в лотках",
|
||
"Гарнир",
|
||
"Хлеб",
|
||
"Кисломолочные",
|
||
"Яйца",
|
||
"Рыба",
|
||
"Масло для готовки"
|
||
],
|
||
"days": 7,
|
||
"users": [
|
||
{
|
||
"id": -1,
|
||
"name": "Иван",
|
||
"gender": "m",
|
||
"age": 30,
|
||
"weight": 87,
|
||
"height": 180,
|
||
"avoid": [
|
||
"Детское питание"
|
||
],
|
||
"favorite": []
|
||
},
|
||
{
|
||
"id": -2,
|
||
"name": "Мария",
|
||
"gender": "f",
|
||
"age": 28,
|
||
"weight": 65,
|
||
"height": 160,
|
||
"avoid": [
|
||
"Детское питание"
|
||
],
|
||
"favorite": [
|
||
"Яблоко"
|
||
]
|
||
},
|
||
{
|
||
"id": -3,
|
||
"name": "Пётр",
|
||
"gender": "m",
|
||
"age": 10,
|
||
"weight": 45,
|
||
"height": 140,
|
||
"avoid": [
|
||
"Алкоголь",
|
||
"Засоленные",
|
||
"Острое"
|
||
],
|
||
"favorite": []
|
||
}
|
||
],
|
||
"cart": [
|
||
[
|
||
{
|
||
"name": "Овощи для жарки, 1кг",
|
||
"n": 1200,
|
||
"price": 23.799,
|
||
"total_price": 142.79399999999998,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/64\/79\/226479.jpg",
|
||
"unit": "g"
|
||
},
|
||
{
|
||
"name": "Картофель фри, 1кг",
|
||
"n": 300,
|
||
"price": 21.799,
|
||
"total_price": 43.598,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/66\/06\/226606.jpg",
|
||
"unit": "g"
|
||
},
|
||
{
|
||
"name": "Свекла соломка уп, 300-500г",
|
||
"n": 400,
|
||
"price": 27.99,
|
||
"total_price": 111.96,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/46\/04\/384604.jpg",
|
||
"unit": "g"
|
||
},
|
||
{
|
||
"name": "Молоко ультрапастеризованное Ам-Ам Мамина забота обогащённое витамином C, 8+ месяцев, 205г",
|
||
"n": 1,
|
||
"price": 47.49,
|
||
"total_price": 47.49,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/23\/26\/4852326.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Смесь Волшебное дерево спагетти болоньезе, 30г",
|
||
"n": 1,
|
||
"price": 72.49,
|
||
"total_price": 72.49,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/98\/53\/4399853.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Хренодер ФЭГ ядрёный, 240г",
|
||
"n": 1,
|
||
"price": 131.99,
|
||
"total_price": 131.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/40\/74\/274074.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Огурцы свежие с укропом, вес",
|
||
"n": 2000,
|
||
"price": 41.99,
|
||
"total_price": 419.90000000000003,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/36\/73\/483673.jpg",
|
||
"unit": "g"
|
||
},
|
||
{
|
||
"name": "Продукт кисломолочный творожный Exponenta Топленое молоко 0%, 250г",
|
||
"n": 2,
|
||
"price": 191.99,
|
||
"total_price": 383.98,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/03\/28\/4180328.jpg",
|
||
"unit": "pcs"
|
||
}
|
||
],
|
||
[
|
||
{
|
||
"name": "Мороженое сливочное Петрохолод Ленинградское Ванильное в шоколадной глазури, 80г",
|
||
"n": 2,
|
||
"price": 47.99,
|
||
"total_price": 95.98,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/17\/67\/2091767.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Капуста белокочанная резаная уп, 400-800г",
|
||
"n": 1800,
|
||
"price": 31.99,
|
||
"total_price": 383.88,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/60\/12\/4476012.jpg",
|
||
"unit": "g"
|
||
},
|
||
{
|
||
"name": "Крем-суп протеиновый Bionova Томатный, 20г",
|
||
"n": 1,
|
||
"price": 71.99,
|
||
"total_price": 71.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/66\/98\/546698.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Креветки королевские варёно-мороженые Agama очищенные, 300г",
|
||
"n": 1,
|
||
"price": 769.99,
|
||
"total_price": 769.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/13\/54\/1221354.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Чипсы нори Naitori со вкусом краба, 3г",
|
||
"n": 1,
|
||
"price": 54.99,
|
||
"total_price": 54.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/65\/19\/4276519.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Салат Белая Дача Botanicum мини руккола, айсберг, романо, 75г",
|
||
"n": 1,
|
||
"price": 184.99,
|
||
"total_price": 184.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/51\/87\/4055187.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Каша рисовая безмолочная HiPP Organic фрукты-злаки с 5 месяцев, 190г",
|
||
"n": 1,
|
||
"price": 216.99,
|
||
"total_price": 216.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/48\/03\/4224803.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Стебель сельдерея в нарезке, вес",
|
||
"n": 300,
|
||
"price": 45.999,
|
||
"total_price": 137.997,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/28\/08\/422808.jpg",
|
||
"unit": "g"
|
||
},
|
||
{
|
||
"name": "Йогурт двухслойный Савушкин манго 2%, 120г",
|
||
"n": 1,
|
||
"price": 32.99,
|
||
"total_price": 32.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/67\/70\/4596770.jpg",
|
||
"unit": "pcs"
|
||
}
|
||
],
|
||
[
|
||
{
|
||
"name": "Котлеты куриные Троекурово, 500г",
|
||
"n": 3,
|
||
"price": 109.99,
|
||
"total_price": 329.96999999999997,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/71\/57\/407157.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Макаронные изделия Ваш выбор Перья, 400г",
|
||
"n": 2,
|
||
"price": 19.99,
|
||
"total_price": 39.98,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/27\/72\/3422772.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Хлеб украинский новый Пеко в упаковке, 650г",
|
||
"n": 2,
|
||
"price": 25.99,
|
||
"total_price": 51.98,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/27\/15\/412715.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Фарш из минтая охлаждённый, вес",
|
||
"n": 600,
|
||
"price": 59.999,
|
||
"total_price": 359.994,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/82\/35\/318235.jpg",
|
||
"unit": "g"
|
||
},
|
||
{
|
||
"name": "Мороженое сливочное На сливочках Ежевика-Малина, 85г",
|
||
"n": 6,
|
||
"price": 92.99,
|
||
"total_price": 557.9399999999999,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/62\/38\/4816238.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Салат Белая Дача Пряная рукола, 50г",
|
||
"n": 3,
|
||
"price": 216.99,
|
||
"total_price": 650.97,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/37\/03\/4663703.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Семена горчицы Мастер Дак, 15 г",
|
||
"n": 1,
|
||
"price": 6.49,
|
||
"total_price": 6.49,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/82\/27\/4858227.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Конфета 35 со вкусом Шоколада, 20г",
|
||
"n": 2,
|
||
"price": 19.99,
|
||
"total_price": 39.98,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/54\/45\/3505445.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Сыр Зеленый в порошке с пажитником 1,4%, 50г",
|
||
"n": 2,
|
||
"price": 173.99,
|
||
"total_price": 347.98,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/33\/28\/3943328.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Смесь грибная быстрозамороженная И Зимой И Летом, 300г",
|
||
"n": 1,
|
||
"price": 351.99,
|
||
"total_price": 351.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/82\/32\/4838232.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Паста соевая Miso тёмная, 1кг",
|
||
"n": 1,
|
||
"price": 449.99,
|
||
"total_price": 449.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/43\/13\/424313.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Клюква дикорастущая Глобус, 300г",
|
||
"n": 1,
|
||
"price": 609.99,
|
||
"total_price": 609.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/90\/39\/3389039.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Соус соевый Тай-Со Классический, 250мл",
|
||
"n": 1,
|
||
"price": 69.99,
|
||
"total_price": 69.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/92\/03\/2489203.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Смесь овощная Мексиканская, 1кг",
|
||
"n": 1200,
|
||
"price": 27.399,
|
||
"total_price": 164.394,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/63\/91\/226391.jpg",
|
||
"unit": "g"
|
||
},
|
||
{
|
||
"name": "Мороженое сливочное Ля Фам Сладкий лимон, 70г",
|
||
"n": 1,
|
||
"price": 51.49,
|
||
"total_price": 51.49,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/69\/64\/4296964.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Каша мультизлаковая безмолочная Сады Придонья яблоко-банан-малина с 6 месяцев, 0,125л",
|
||
"n": 1,
|
||
"price": 32.99,
|
||
"total_price": 32.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/34\/03\/713403.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Кальмар гигантский Глобус без кожицы, 185г",
|
||
"n": 1,
|
||
"price": 199.99,
|
||
"total_price": 199.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/27\/07\/4752707.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Треска тихоокеанская мороженая Глобус филе-кусок с кожей, 500г",
|
||
"n": 1,
|
||
"price": 709.99,
|
||
"total_price": 709.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/99\/73\/1389973.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Тунец полосатый натуральный Морской котик стерилизованный филе, 170г",
|
||
"n": 1,
|
||
"price": 203.99,
|
||
"total_price": 203.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/86\/75\/508675.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Крем-суп протеиновый Bionova Сырный, 20г",
|
||
"n": 1,
|
||
"price": 72.99,
|
||
"total_price": 72.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/67\/00\/546700.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Салат Tango mix Белая Дача рукола, мангольд, 50г",
|
||
"n": 1,
|
||
"price": 218.99,
|
||
"total_price": 218.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/11\/08\/4401108.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Картофель отварной уп, 500-650г",
|
||
"n": 2400,
|
||
"price": 35.99,
|
||
"total_price": 431.88,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/60\/81\/4476081.jpg",
|
||
"unit": "g"
|
||
},
|
||
{
|
||
"name": "Йогурт греческий Venn's натуральный 0,1%, 130г",
|
||
"n": 1,
|
||
"price": 56.99,
|
||
"total_price": 56.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/02\/47\/4160247.jpg",
|
||
"unit": "pcs"
|
||
}
|
||
],
|
||
[
|
||
{
|
||
"name": "Лук репчатый, вес",
|
||
"n": 900,
|
||
"price": 4.899,
|
||
"total_price": 44.091,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/74\/39\/287439.jpg",
|
||
"unit": "g"
|
||
},
|
||
{
|
||
"name": "Какао+ Экологика стевия + пребиотик, 125г",
|
||
"n": 1,
|
||
"price": 569.99,
|
||
"total_price": 569.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/64\/31\/846431.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Дрожжи хлебопекарные Ваш выбор сухие, 12г",
|
||
"n": 3,
|
||
"price": 8.99,
|
||
"total_price": 26.97,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/79\/28\/4157928.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Смесь овощная Лечо, 1кг",
|
||
"n": 1200,
|
||
"price": 27.299,
|
||
"total_price": 163.79399999999998,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/64\/80\/226480.jpg",
|
||
"unit": "g"
|
||
},
|
||
{
|
||
"name": "Огурцы солёные Традиции вкуса, 300г",
|
||
"n": 1,
|
||
"price": 121.99,
|
||
"total_price": 121.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/81\/54\/868154.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Маршмеллоу Мини Guandy белый ванильный, 75г",
|
||
"n": 1,
|
||
"price": 94.49,
|
||
"total_price": 94.49,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/86\/03\/1578603.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Перец красный Мастер Дак молотый, 10г",
|
||
"n": 1,
|
||
"price": 8.99,
|
||
"total_price": 8.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/23\/41\/252341.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Молоко сгущенное цельное Алексеевское с сахаром, стик 8,5%, 7г",
|
||
"n": 1,
|
||
"price": 4.99,
|
||
"total_price": 4.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/56\/82\/4095682.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Овощное ассорти острое ФЭГ, 800г",
|
||
"n": 1,
|
||
"price": 195.99,
|
||
"total_price": 195.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/05\/48\/300548.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Концентрированный сухой бульон Ассорти Kruglie Sutki Коллаген, 75г",
|
||
"n": 1,
|
||
"price": 749.99,
|
||
"total_price": 749.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/10\/08\/prd_810461008.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Хлебцы экструзионные Три Грации с томатом и прованскими травами, 55г",
|
||
"n": 1,
|
||
"price": 43.49,
|
||
"total_price": 43.49,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/63\/61\/4106361.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Соус соевый Yatomi, 30г",
|
||
"n": 1,
|
||
"price": 31.99,
|
||
"total_price": 31.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/83\/72\/3778372.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Помидоры протертые Burcu, 350г",
|
||
"n": 1,
|
||
"price": 204.99,
|
||
"total_price": 204.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/09\/82\/4400982.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Чеснок резаный LiViAnTa, 100г",
|
||
"n": 1,
|
||
"price": 203.99,
|
||
"total_price": 203.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/89\/78\/4818978.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Творог обезжиренный Рузское молоко, 200г",
|
||
"n": 1,
|
||
"price": 145.99,
|
||
"total_price": 145.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/46\/06\/644606.jpg",
|
||
"unit": "pcs"
|
||
}
|
||
],
|
||
[
|
||
{
|
||
"name": "Молоко из Вологды с витаминами и йодом для хороших оценок 3,2%, 200мл",
|
||
"n": 9,
|
||
"price": 39.99,
|
||
"total_price": 359.91,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/02\/64\/4160264.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Продукт йогуртный Нежный с соком клубники 1,2%, 100г",
|
||
"n": 8,
|
||
"price": 23.49,
|
||
"total_price": 187.92,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/50\/67\/4895067.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Яйца куриные столовые Синявинское С0 белое, 30г",
|
||
"n": 2,
|
||
"price": 389.99,
|
||
"total_price": 779.98,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/38\/51\/4233851.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Шеи цыплят-бройлеров охлаждённые Троекурово, 500г",
|
||
"n": 3,
|
||
"price": 109.99,
|
||
"total_price": 329.96999999999997,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/79\/84\/3967984.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Хлебцы хрустящие Ого! Столовые, 75г",
|
||
"n": 4,
|
||
"price": 32.99,
|
||
"total_price": 131.96,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/25\/46\/3432546.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Творог обезжиренный Козельский Живой, 180г",
|
||
"n": 2,
|
||
"price": 103.99,
|
||
"total_price": 207.98,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/24\/06\/1502406.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Мята перечная сушёная Приправыч, 6г",
|
||
"n": 1,
|
||
"price": 23.99,
|
||
"total_price": 23.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/91\/92\/4359192.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Микрозелень редиса санго MaxiFermer, 50г",
|
||
"n": 4,
|
||
"price": 215.99,
|
||
"total_price": 863.96,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/54\/88\/4385488.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Перец Mikado Халапеньо резанный зеленый, 350мл",
|
||
"n": 1,
|
||
"price": 217.99,
|
||
"total_price": 217.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/78\/05\/4887805.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Ветчина Сочная Мираторг нарезка, 160г",
|
||
"n": 1,
|
||
"price": 179.99,
|
||
"total_price": 179.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/04\/69\/3460469.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Лук зелёный Глобус перо, 250г",
|
||
"n": 1,
|
||
"price": 171.99,
|
||
"total_price": 171.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/19\/63\/271963.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Щавель Богослово Арго свежий, 100г",
|
||
"n": 3,
|
||
"price": 217.99,
|
||
"total_price": 653.97,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/77\/01\/277701.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Яблоки Айдаред, вес",
|
||
"n": 1600,
|
||
"price": 20.999000000000002,
|
||
"total_price": 167.99200000000002,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/10\/40\/3991040.jpg",
|
||
"unit": "g"
|
||
},
|
||
{
|
||
"name": "Яблочные слайсы Яблоков, 25г",
|
||
"n": 3,
|
||
"price": 96.49,
|
||
"total_price": 289.46999999999997,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/32\/15\/3693215.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Борщ быстрорастворимый Кнорр Чашка Супа с сухариками, 14,8г",
|
||
"n": 2,
|
||
"price": 28.49,
|
||
"total_price": 56.98,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/70\/36\/4457036.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Весенние овощи, 1кг",
|
||
"n": 8100,
|
||
"price": 29.199,
|
||
"total_price": 788.373,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/64\/70\/226470.jpg",
|
||
"unit": "g"
|
||
},
|
||
{
|
||
"name": "Васаби Глобус, 5г",
|
||
"n": 2,
|
||
"price": 19.99,
|
||
"total_price": 39.98,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/77\/17\/4757717.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Желе Jele Beautie cо вкусом клубники, 140г",
|
||
"n": 2,
|
||
"price": 169.99,
|
||
"total_price": 339.98,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/15\/40\/4661540.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Шампанское Champagne M. Ferat & Fils Brut Blanc de Blancs Premier Cru белое брют 12% алк., Франция, 750мл",
|
||
"n": 1,
|
||
"price": 8869.99,
|
||
"total_price": 8869.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/44\/86\/4704486.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Пастила Пастилушка яблоко-вишня, 1кг",
|
||
"n": 50,
|
||
"price": 73.999,
|
||
"total_price": 73.999,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/44\/09\/4274409.jpg",
|
||
"unit": "g"
|
||
},
|
||
{
|
||
"name": "Перец Халапеньо Kühne резаный, 330г",
|
||
"n": 1,
|
||
"price": 478.99,
|
||
"total_price": 478.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/51\/55\/375155.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Салатный микс Браво Белая Дача Шпинат, мангольд, рукола, 50г",
|
||
"n": 1,
|
||
"price": 213.99,
|
||
"total_price": 213.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/36\/97\/4663697.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Закуска Пиканта Астраханская, 460г",
|
||
"n": 1,
|
||
"price": 161.99,
|
||
"total_price": 161.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/14\/17\/3421417.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Семя горчицы Приправыч, 20г",
|
||
"n": 1,
|
||
"price": 13.49,
|
||
"total_price": 13.49,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/91\/74\/4359174.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Напиток спортивный ProteinRex BCAA 6000мг бабл-гам, 500мл",
|
||
"n": 2,
|
||
"price": 109.99,
|
||
"total_price": 219.98,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/00\/15\/4740015.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Дрожжи универсальные Dr. Bakers быстродействующие, 7г",
|
||
"n": 1,
|
||
"price": 29.99,
|
||
"total_price": 29.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/22\/31\/3612231.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Сироп низкокалорийный Mr. Djemius Zero кленовый без сахара, 330г",
|
||
"n": 1,
|
||
"price": 351.99,
|
||
"total_price": 351.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/40\/14\/4314014.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Тыква уп, 0,4-1кг",
|
||
"n": 800,
|
||
"price": 55.99,
|
||
"total_price": 223.96,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/18\/37\/411837.jpg",
|
||
"unit": "g"
|
||
},
|
||
{
|
||
"name": "Ветчина варёная по-клински Клинский Для тостов, нарезка, 120г",
|
||
"n": 2,
|
||
"price": 121.99,
|
||
"total_price": 243.98,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/72\/11\/3007211.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Шиповник сушёный ФруктОрешки, 200г",
|
||
"n": 1,
|
||
"price": 106.99,
|
||
"total_price": 106.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/58\/79\/255879.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Чипсы нори Sen Soy Оригинал, 4,5г",
|
||
"n": 3,
|
||
"price": 81.49,
|
||
"total_price": 244.46999999999997,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/21\/64\/4042164.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Грибное ассорти в маринаде Lutik, 530г",
|
||
"n": 1,
|
||
"price": 264.99,
|
||
"total_price": 264.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/72\/51\/3497251.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Морковь отварная кубик уп, 450-550г",
|
||
"n": 1200,
|
||
"price": 35.99,
|
||
"total_price": 215.94,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/46\/13\/384613.jpg",
|
||
"unit": "g"
|
||
},
|
||
{
|
||
"name": "Баклажаны резаные, вес",
|
||
"n": 800,
|
||
"price": 47.999,
|
||
"total_price": 191.996,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/28\/01\/422801.jpg",
|
||
"unit": "g"
|
||
},
|
||
{
|
||
"name": "Гречка Preston с мясом, 40г",
|
||
"n": 1,
|
||
"price": 32.49,
|
||
"total_price": 32.49,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/55\/57\/1225557.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Салака мороженая, вес",
|
||
"n": 100,
|
||
"price": 31.599,
|
||
"total_price": 31.599,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/49\/13\/264913.jpg",
|
||
"unit": "g"
|
||
},
|
||
{
|
||
"name": "Печенье StMichel сливочное с шоколадом, 132г",
|
||
"n": 1,
|
||
"price": 519.99,
|
||
"total_price": 519.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/22\/80\/4842280.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Дрожжи Парфэ Декор быстродействующие, 11г",
|
||
"n": 1,
|
||
"price": 18.49,
|
||
"total_price": 18.49,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/83\/18\/4868318.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Микс водорослей Морская капуста с фукусом Здоровье для салата, 400г",
|
||
"n": 1,
|
||
"price": 182.99,
|
||
"total_price": 182.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/29\/00\/1582900.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Чипсы нори Глобус Токи поки, 5г",
|
||
"n": 1,
|
||
"price": 62.99,
|
||
"total_price": 62.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/57\/65\/4435765.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Шиповник сушёный Isfarafood отборный, 500г",
|
||
"n": 1,
|
||
"price": 238.99,
|
||
"total_price": 238.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/08\/01\/700801.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Морковь резаная палочками уп, 200-300г",
|
||
"n": 100,
|
||
"price": 39.99,
|
||
"total_price": 39.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/46\/01\/384601.jpg",
|
||
"unit": "g"
|
||
},
|
||
{
|
||
"name": "Молоко Parmalat 0,5%, 1л",
|
||
"n": 1,
|
||
"price": 149.99,
|
||
"total_price": 149.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/21\/68\/3872168.jpg",
|
||
"unit": "pcs"
|
||
}
|
||
],
|
||
[
|
||
{
|
||
"name": "Путассу замороженная неразделанная, вес",
|
||
"n": 2000,
|
||
"price": 16.899,
|
||
"total_price": 168.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/91\/35\/4289135.jpg",
|
||
"unit": "g"
|
||
},
|
||
{
|
||
"name": "Приправа для гриля Мастер Дак, 15г",
|
||
"n": 2,
|
||
"price": 14.49,
|
||
"total_price": 28.98,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/53\/55\/4725355.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Паста соевая мисо Wanjia Shinshumiso светлая, 1кг",
|
||
"n": 1,
|
||
"price": 458.99,
|
||
"total_price": 458.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/26\/72\/3832672.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Ламинария Вегана, 150г",
|
||
"n": 1,
|
||
"price": 629.99,
|
||
"total_price": 629.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/85\/35\/148535.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Псиллиум Look Green, 120г",
|
||
"n": 1,
|
||
"price": 539.99,
|
||
"total_price": 539.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/87\/76\/4838776.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Какао-напиток растворимый Шокомишка, 20*14г",
|
||
"n": 4,
|
||
"price": 15.49,
|
||
"total_price": 61.96,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/30\/61\/4773061.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Соус Терияки Yatomi, 30г",
|
||
"n": 5,
|
||
"price": 19.99,
|
||
"total_price": 99.94999999999999,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/75\/26\/3607526.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Васаби Yatomi, 5г",
|
||
"n": 3,
|
||
"price": 21.49,
|
||
"total_price": 64.47,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/83\/74\/3778374.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Шампиньоны резаные, 1кг",
|
||
"n": 2000,
|
||
"price": 31.999000000000002,
|
||
"total_price": 319.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/66\/05\/226605.jpg",
|
||
"unit": "g"
|
||
},
|
||
{
|
||
"name": "Халапеньо красный Глобус, 360г",
|
||
"n": 2,
|
||
"price": 146.99,
|
||
"total_price": 293.98,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/45\/28\/4324528.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Капуста квашеная, вес",
|
||
"n": 200,
|
||
"price": 39.99,
|
||
"total_price": 79.98,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/07\/57\/470757.jpg",
|
||
"unit": "g"
|
||
},
|
||
{
|
||
"name": "Крем-суп протеиновый Bionova Грибной, 20г",
|
||
"n": 3,
|
||
"price": 65.49,
|
||
"total_price": 196.46999999999997,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/66\/96\/546696.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Молоко для питания детей Эконива с 3 лет 3,2%, 200мл",
|
||
"n": 8,
|
||
"price": 39.99,
|
||
"total_price": 319.92,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/70\/45\/617045.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Йогурт Простоквашино с клубникой 2,9%, 110г",
|
||
"n": 4,
|
||
"price": 29.99,
|
||
"total_price": 119.96,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/42\/39\/3474239.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Конфеты вафельные Обыкновенное чудо сливочное, 55г",
|
||
"n": 2,
|
||
"price": 39.49,
|
||
"total_price": 78.98,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/46\/99\/144699.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Макаронные изделия Ваш выбор Рожки, 400г",
|
||
"n": 2,
|
||
"price": 18.99,
|
||
"total_price": 37.98,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/20\/43\/3952043.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Огурцы соленые корнишоны, вес",
|
||
"n": 200,
|
||
"price": 45.99,
|
||
"total_price": 91.98,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/86\/07\/488607.jpg",
|
||
"unit": "g"
|
||
},
|
||
{
|
||
"name": "Тефтели из мяса цыплёнка-бройлера Троекурово, 350г",
|
||
"n": 1,
|
||
"price": 139.99,
|
||
"total_price": 139.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/85\/06\/3068506.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Мороженое сливочное Ла-ла-бу-бу стакан вафельный шоко-бабл с шариками, 70г",
|
||
"n": 2,
|
||
"price": 81.49,
|
||
"total_price": 162.98,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/63\/22\/4816322.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Пастила Пастилушка кусочки, 40г",
|
||
"n": 1,
|
||
"price": 36.49,
|
||
"total_price": 36.49,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/44\/11\/4274411.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Смесь для пудинга Haas Шоколадный, 40г",
|
||
"n": 1,
|
||
"price": 38.99,
|
||
"total_price": 38.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/71\/91\/3927191.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Батончик фруктовый Pikki Чернослив, 25г",
|
||
"n": 1,
|
||
"price": 54.49,
|
||
"total_price": 54.49,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/59\/84\/915984.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Стрипсы куриные Троекурово острые, 350г",
|
||
"n": 1,
|
||
"price": 199.99,
|
||
"total_price": 199.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/23\/28\/1342328.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Молоко обезжиренное Viola UHT 0,05%, 971мл",
|
||
"n": 2,
|
||
"price": 149.99,
|
||
"total_price": 299.98,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/20\/70\/3902070.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Свёкла отварная уп, 500-600г",
|
||
"n": 400,
|
||
"price": 35.99,
|
||
"total_price": 71.98,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/64\/71\/1156471.jpg",
|
||
"unit": "g"
|
||
}
|
||
],
|
||
[
|
||
{
|
||
"name": "Хлеб пшеничный белый Пеко, 380г",
|
||
"n": 1,
|
||
"price": 21.99,
|
||
"total_price": 21.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/90\/88\/3829088.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Чипсы из морской капусты Kakao Friends классические, в ассортименте, 2г",
|
||
"n": 7,
|
||
"price": 59.49,
|
||
"total_price": 416.43,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/15\/37\/3801537.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Цикорий растворимый Elite без кофеина, 75г",
|
||
"n": 1,
|
||
"price": 76.99,
|
||
"total_price": 76.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/11\/03\/2931103.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Пастила Зеленика финиковая, 5шт, 60г",
|
||
"n": 1,
|
||
"price": 88.49,
|
||
"total_price": 88.49,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/68\/34\/4736834.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Протертая мякоть томатов Пиканта с базиликом Пассата, 220г",
|
||
"n": 2,
|
||
"price": 104.99,
|
||
"total_price": 209.98,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/25\/96\/4762596.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Салат Латук свежий листовой в горшочке, 100г",
|
||
"n": 3,
|
||
"price": 82.49,
|
||
"total_price": 247.46999999999997,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/98\/29\/4979829.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Грибы лисички сухие Грибной дождь, 30г",
|
||
"n": 1,
|
||
"price": 483.99,
|
||
"total_price": 483.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/65\/56\/4816556.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Микрозелень подсолнечника MaxiFermer, 50г",
|
||
"n": 2,
|
||
"price": 215.99,
|
||
"total_price": 431.98,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/54\/92\/4385492.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Карамель Кремка с молочным вкусом, вес",
|
||
"n": 90,
|
||
"price": 37.39,
|
||
"total_price": 112.17,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/80\/91\/4468091.jpg",
|
||
"unit": "g"
|
||
},
|
||
{
|
||
"name": "Продукт йогуртный Сливочное лакомство Fruttis в ассортименте: Клубника, Персик 5%, 115г",
|
||
"n": 5,
|
||
"price": 36.49,
|
||
"total_price": 182.45000000000002,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/33\/89\/4143389.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Творог мягкий обезжиренный Простоквашино, 120г",
|
||
"n": 3,
|
||
"price": 47.99,
|
||
"total_price": 143.97,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/00\/33\/4260033.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Чипсы нори Naitori со вкусом кимчи, 3г",
|
||
"n": 3,
|
||
"price": 52.99,
|
||
"total_price": 158.97,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/65\/21\/4276521.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Набор для тушения из цыплят-бройлеров Верхневолжская птицефабрика уп, 0,8-1,1кг",
|
||
"n": 2500,
|
||
"price": 99.99,
|
||
"total_price": 999.9,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/82\/33\/3168233.jpg",
|
||
"unit": "g"
|
||
},
|
||
{
|
||
"name": "Хлеб Станичный, половинка, 350г",
|
||
"n": 1,
|
||
"price": 47.49,
|
||
"total_price": 47.49,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/36\/97\/403697.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Паприка Мастер Дак молотая, 10г",
|
||
"n": 2,
|
||
"price": 9.99,
|
||
"total_price": 19.98,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/23\/43\/252343.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Смесь компотная, 1кг",
|
||
"n": 450,
|
||
"price": 39.999,
|
||
"total_price": 119.99700000000001,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/58\/02\/4235802.jpg",
|
||
"unit": "g"
|
||
},
|
||
{
|
||
"name": "Лук зелёный Глобус, 100г",
|
||
"n": 2,
|
||
"price": 89.99,
|
||
"total_price": 179.98,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/09\/59\/380959.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Суп белковый Ironman Fit куриный с ароматными травами, 20г",
|
||
"n": 2,
|
||
"price": 93.49,
|
||
"total_price": 186.98,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/75\/87\/1867587.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Цветная капуста, 1кг",
|
||
"n": 1200,
|
||
"price": 34.599000000000004,
|
||
"total_price": 207.59400000000002,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/74\/50\/377450.jpg",
|
||
"unit": "g"
|
||
},
|
||
{
|
||
"name": "Молоко из Вологды для детей с 3 лет 3,2%, 200мл",
|
||
"n": 3,
|
||
"price": 39.99,
|
||
"total_price": 119.97,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/02\/65\/4160265.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Отруби овсяные Мистраль Энергия и бодрость, 30г",
|
||
"n": 1,
|
||
"price": 59.99,
|
||
"total_price": 59.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/50\/98\/1785098.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Икра трески Беринг подкопченная, 125г",
|
||
"n": 1,
|
||
"price": 168.99,
|
||
"total_price": 168.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/05\/68\/260568.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Ветчина Мясной Дом Бородина в синюге уп, 0,9-1,1кг",
|
||
"n": 50,
|
||
"price": 999.99,
|
||
"total_price": 999.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/73\/17\/3937317.jpg",
|
||
"unit": "g"
|
||
},
|
||
{
|
||
"name": "Продукт йогуртный Нежный с соком вишни 1,2%, 100г",
|
||
"n": 2,
|
||
"price": 23.99,
|
||
"total_price": 47.98,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/50\/63\/4895063.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Хамса пряного посола, вес",
|
||
"n": 100,
|
||
"price": 29.99,
|
||
"total_price": 29.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/26\/37\/322637.jpg",
|
||
"unit": "g"
|
||
},
|
||
{
|
||
"name": "Печенье протеиновое Butter Wave сливочное, 36г",
|
||
"n": 1,
|
||
"price": 103.99,
|
||
"total_price": 103.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/62\/32\/3786232.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Килька пряного посола, вес",
|
||
"n": 50,
|
||
"price": 34.99,
|
||
"total_price": 34.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/27\/91\/422791.jpg",
|
||
"unit": "g"
|
||
},
|
||
{
|
||
"name": "Масло сливочное Лебедяньмолоко Крестьянское 72,5%, 180г",
|
||
"n": 1,
|
||
"price": 169.99,
|
||
"total_price": 169.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/19\/38\/4461938.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Отбивная из индейки охлажденная Пава Пава, 300г",
|
||
"n": 3,
|
||
"price": 309.99,
|
||
"total_price": 929.97,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/48\/32\/3844832.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Свёкла отварная соломка, вес",
|
||
"n": 450,
|
||
"price": 35.999,
|
||
"total_price": 107.99700000000001,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/60\/65\/4476065.jpg",
|
||
"unit": "g"
|
||
},
|
||
{
|
||
"name": "Лук красный, кольца уп, 400-600г",
|
||
"n": 200,
|
||
"price": 34.99,
|
||
"total_price": 69.98,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/46\/03\/384603.jpg",
|
||
"unit": "g"
|
||
},
|
||
{
|
||
"name": "Крупа из полбы Чёрный хлеб дроблёная, 500г",
|
||
"n": 1,
|
||
"price": 285.99,
|
||
"total_price": 285.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/96\/65\/689665.jpg",
|
||
"unit": "pcs"
|
||
},
|
||
{
|
||
"name": "Молоко безлактозное Protein Max Molvest 0,5%, 450г",
|
||
"n": 1,
|
||
"price": 114.99,
|
||
"total_price": 114.99,
|
||
"currency": "rub",
|
||
"image": "https:\/\/hvatilo.ru\/static\/retail\/ru\/image.globus\/{SIZE}\/mobile\/26\/27\/4872627.jpg",
|
||
"unit": "pcs"
|
||
}
|
||
]
|
||
],
|
||
"excess": 0.5362191665220106,
|
||
"precision": 98.14517264634198
|
||
};
|
||
|
||
const loadInitData = (async function() {
|
||
return fetch(host + '/api/promo/get_initial_data', {credentials: 'include'})
|
||
.then(async response => {
|
||
const data = await response.json();
|
||
|
||
if (response.status === 400) {
|
||
return requestWithRefresh(host + '/api/guest/clear_cookie', {method: 'POST'})
|
||
.then(r => {document.location.reload()});
|
||
}
|
||
if (response.status === 401 && data.error_message !== 'need_refresh') {
|
||
await initToken();
|
||
await new Promise(resolve => setTimeout(() => resolve(), 100));
|
||
return fetch(host + '/api/promo/get_initial_data', {credentials: 'include'})
|
||
.then(r => r.json());
|
||
}
|
||
if (response.status === 403 || data.error_message === 'need_refresh') {
|
||
return await refreshToken()
|
||
.then((r) => {
|
||
return fetch(host + '/api/promo/get_initial_data', {credentials: 'include'})
|
||
.then(r => r.json());
|
||
});
|
||
}
|
||
return data;
|
||
})
|
||
.then((data) => {
|
||
updateCart();
|
||
return data;
|
||
})
|
||
.catch(error => {
|
||
// return Promise.resolve(mockData);
|
||
return Promise.resolve({
|
||
cart: [],
|
||
users: [],
|
||
initial_groups: [],
|
||
available_groups: [],
|
||
days: 7,
|
||
});
|
||
})
|
||
});
|
||
|
||
/**
|
||
* Дебаунс с группировкой идентификаторов и очередью.
|
||
*
|
||
* @param {Function} func - функция, принимающая массив ID и возвращающая Promise
|
||
* @param {number} delay - задержка в мс между последним кликом и отправкой запроса
|
||
* @returns {Function} - дебаунсированная функция, принимающая один ID и возвращающая Promise
|
||
*/
|
||
function debounceBatch(func, delay) {
|
||
let timerId = null;
|
||
let pendingBatch = null; // ожидает таймера
|
||
let runningBatch = null; // выполняется
|
||
let nextBatch = null; // накапливается во время выполнения
|
||
|
||
function processBatch(batch) {
|
||
runningBatch = batch;
|
||
const { ids, promises } = batch;
|
||
|
||
let result;
|
||
try {
|
||
result = func(ids);
|
||
} catch (err) {
|
||
promises.forEach(p => p.reject(err));
|
||
finishBatch();
|
||
return;
|
||
}
|
||
|
||
if (result && typeof result.then === 'function') {
|
||
result
|
||
.then(data => promises.forEach(p => p.resolve(data)))
|
||
.catch(err => promises.forEach(p => p.reject(err)))
|
||
.finally(finishBatch);
|
||
} else {
|
||
promises.forEach(p => p.resolve(result));
|
||
finishBatch();
|
||
}
|
||
}
|
||
|
||
function finishBatch() {
|
||
runningBatch = null;
|
||
// Если есть накопленный следующий батч – переносим в ожидающие и запускаем таймер
|
||
if (nextBatch && nextBatch.ids.length > 0) {
|
||
pendingBatch = nextBatch;
|
||
nextBatch = null;
|
||
timerId = setTimeout(() => {
|
||
timerId = null;
|
||
const batch = pendingBatch;
|
||
pendingBatch = null;
|
||
processBatch(batch);
|
||
}, delay);
|
||
}
|
||
}
|
||
|
||
return function debounced(id) {
|
||
return new Promise((resolve, reject) => {
|
||
if (runningBatch) {
|
||
// Во время выполнения – добавляем в nextBatch
|
||
if (!nextBatch) {
|
||
nextBatch = { ids: [], promises: [] };
|
||
}
|
||
nextBatch.ids.push(id);
|
||
nextBatch.promises.push({ resolve, reject });
|
||
} else if (pendingBatch) {
|
||
// Ожидает таймера – добавляем и перезапускаем таймер
|
||
pendingBatch.ids.push(id);
|
||
pendingBatch.promises.push({ resolve, reject });
|
||
clearTimeout(timerId);
|
||
timerId = setTimeout(() => {
|
||
timerId = null;
|
||
const batch = pendingBatch;
|
||
pendingBatch = null;
|
||
processBatch(batch);
|
||
}, delay);
|
||
} else {
|
||
// Ничего нет – создаём новый ожидающий батч
|
||
pendingBatch = { ids: [id], promises: [{ resolve, reject }] };
|
||
timerId = setTimeout(() => {
|
||
timerId = null;
|
||
const batch = pendingBatch;
|
||
pendingBatch = null;
|
||
processBatch(batch);
|
||
}, delay);
|
||
}
|
||
});
|
||
};
|
||
}
|
||
|
||
function debounce(func, delay) {
|
||
let timeoutId;
|
||
let rejectPrevious; // функция для отклонения предыдущего промиса
|
||
|
||
return function (...args) {
|
||
// Если есть ожидающий промис, отклоняем его
|
||
if (rejectPrevious) {
|
||
rejectPrevious(new Error('Debounced function cancelled'));
|
||
rejectPrevious = null;
|
||
}
|
||
|
||
// Создаём новый промис для текущего вызова
|
||
return new Promise((resolve, reject) => {
|
||
// Сохраняем reject, чтобы можно было отклонить этот промис позже
|
||
rejectPrevious = reject;
|
||
|
||
// Очищаем старый таймер и устанавливаем новый
|
||
clearTimeout(timeoutId);
|
||
timeoutId = setTimeout(() => {
|
||
try {
|
||
// Вызываем оригинальную функцию с переданными аргументами и контекстом
|
||
const result = func.apply(this, args);
|
||
|
||
// Если результат — промис, дожидаемся его
|
||
if (result && typeof result.then === 'function') {
|
||
result.then(resolve).catch(reject);
|
||
} else {
|
||
resolve(result);
|
||
}
|
||
} catch (error) {
|
||
reject(error);
|
||
} finally {
|
||
// Сбрасываем, чтобы не отклонить случайно после выполнения
|
||
rejectPrevious = null;
|
||
}
|
||
}, delay);
|
||
});
|
||
};
|
||
}
|
||
|
||
let allProducts;
|
||
let visibleProducts;
|
||
|
||
function renderProduct(item, index) {
|
||
const li = document.createElement('li');
|
||
li.className = 'cart-item';
|
||
const amount = item.unit === 'g' ? item.n + ' г' : item.n + ' шт';
|
||
li.innerHTML = cartPolicy.createHTML(`
|
||
<div class="item-image"><img src="${item.image}" alt=""></div>
|
||
<div class="item-details">
|
||
<div class="item-name">${item.name}</div>
|
||
<div class="item-price">${amount} × ${Math.round(item.price * 100) / 100} ₽</div>
|
||
</div>
|
||
<div class="menu-btn-wrapper">
|
||
<button class="menu-btn" data-index="${index}">⋮</button>
|
||
<div class="menu-dropdown">
|
||
<ul>
|
||
<li class="menu-replace">Заменить</li>
|
||
<li class="menu-remove">Удалить</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
`);
|
||
return li;
|
||
}
|
||
|
||
|
||
let cartList;
|
||
let scrollWrapper;
|
||
let showMoreBtn;
|
||
let remainingSpan;
|
||
let initialData_g;
|
||
|
||
const cartPolicy = window.trustedTypes.createPolicy('cartPolicy', {
|
||
createHTML: (string) => string
|
||
});
|
||
|
||
function renderProducts() {
|
||
const existingNodesByKey = new Map();
|
||
|
||
Array.from(cartList.children).forEach(node => {
|
||
existingNodesByKey.set(node.dataset.productKey, node);
|
||
});
|
||
|
||
visibleProducts.forEach((item, index) => {
|
||
const key = item.name;
|
||
const signature = JSON.stringify({
|
||
name: item.name,
|
||
n: item.n,
|
||
price: item.price,
|
||
total_price: item.total_price,
|
||
currency: item.currency,
|
||
image: item.image,
|
||
unit: item.unit,
|
||
});
|
||
|
||
let node = existingNodesByKey.get(key);
|
||
|
||
if (!node || node.dataset.productSignature !== signature) {
|
||
const oldNode = node;
|
||
|
||
node = renderProduct(item, index);
|
||
node.dataset.productKey = key;
|
||
node.dataset.productSignature = signature;
|
||
|
||
node.getElementsByClassName('item-image')[0].addEventListener('click', () => openModal(
|
||
item.image.replace('65,fit', '335,fit'),
|
||
item.name,
|
||
item.n,
|
||
item.total_price,
|
||
() => { console.log('replace') },
|
||
() => { console.log('another') },
|
||
));
|
||
|
||
if (oldNode) {
|
||
oldNode.replaceWith(node);
|
||
}
|
||
} else {
|
||
const menuBtn = node.querySelector('.menu-btn');
|
||
if (menuBtn) {
|
||
menuBtn.dataset.index = index;
|
||
}
|
||
}
|
||
|
||
const currentNodeAtPosition = cartList.children[index];
|
||
|
||
if (currentNodeAtPosition !== node) {
|
||
cartList.insertBefore(node, currentNodeAtPosition || null);
|
||
}
|
||
|
||
existingNodesByKey.delete(key);
|
||
});
|
||
|
||
existingNodesByKey.forEach(node => {
|
||
node.remove();
|
||
});
|
||
|
||
const remaining = allProducts.length - visibleProducts.length;
|
||
if(remaining > 0) {
|
||
showMoreBtn.classList.remove('hidden');
|
||
remainingSpan.textContent = remaining;
|
||
} else {
|
||
showMoreBtn.classList.add('hidden');
|
||
}
|
||
|
||
updateSummaryCount();
|
||
calculateListHeight();
|
||
}
|
||
function updateSummaryCount() {
|
||
const totalPrice = new Intl.NumberFormat("ru-RU", { style: "currency", currency: "RUB" }).format(
|
||
Math.round(allProducts.reduce((sum, item) => sum + item.total_price, 0) * 100) / 100,
|
||
);
|
||
const x = Math.round(initialData_g.days * initialData_g.excess + initialData_g.days);
|
||
if(allProducts.length === 0) {
|
||
document.getElementById('summary-details').innerHTML = cartPolicy.createHTML(``);
|
||
document.getElementById('empty-cart-loader').classList.remove('hidden');
|
||
} else {
|
||
document.getElementById('empty-cart-loader').classList.add('hidden');
|
||
document.getElementById('summary-details').innerHTML = cartPolicy.createHTML(`<span>${allProducts.length} ${declension(allProducts.length, ['товар', 'товара', 'товаров'])}</span> <b>•</b> <span>${totalPrice}</span> <div class="summary-excess">С запасами на ${x} ${declension(x, ['день', 'дня', 'дней'])}</div>`);
|
||
document.getElementById('total-price').innerHTML = cartPolicy.createHTML(`${totalPrice}`);
|
||
}
|
||
}
|
||
function calculateListHeight() {
|
||
const leftCol = document.querySelector('.col-left');
|
||
if (!leftCol) return;
|
||
const title = leftCol.querySelector('h1');
|
||
const subtitle = leftCol.querySelector('.subtitle');
|
||
const summary = leftCol.querySelector('.cart-summary');
|
||
const footer = leftCol.querySelector('.cart-footer');
|
||
const showMore = leftCol.querySelector('.show-more');
|
||
|
||
let fixedHeight = 0;
|
||
if(title) fixedHeight += title.offsetHeight + 6;
|
||
if(subtitle) fixedHeight += subtitle.offsetHeight + 28;
|
||
if(summary) fixedHeight += summary.offsetHeight + 24;
|
||
if(showMore && !showMore.classList.contains('hidden')) fixedHeight += showMore.offsetHeight;
|
||
if(footer) fixedHeight += footer.offsetHeight + 20;
|
||
|
||
const paddingY = 60;
|
||
const rect = leftCol.getBoundingClientRect();
|
||
const availHeight = window.innerHeight - rect.top - paddingY - 20;
|
||
|
||
const listHeight = availHeight - fixedHeight;
|
||
if(listHeight > 100) {
|
||
scrollWrapper.style.maxHeight = `${listHeight}px`;
|
||
scrollWrapper.style.overflowY = 'auto';
|
||
}
|
||
}
|
||
function declension(number, titles) {
|
||
const cases = [2, 0, 1, 1, 1, 2];
|
||
const idx = (number % 100 > 4 && number % 100 < 20)
|
||
? 2
|
||
: cases[Math.min(number % 10, 5)];
|
||
return titles[idx];
|
||
}
|
||
|
||
function wholeRender(initialData) {
|
||
initialData_g = initialData;
|
||
document.querySelector('.summary-days').textContent = `${initialData_g.days} ${declension(initialData_g.days, ['день', 'дня', 'дней'])}`;
|
||
allProducts = (Array.isArray(initialData_g.cart) ? initialData_g.cart : [] ?? []).flat().map(item => {
|
||
return {...item, image: item.image?.replace('{SIZE}', '65,fit')}
|
||
});
|
||
visibleProducts = allProducts.slice(0, visibleProducts ? visibleProducts.length : 5);
|
||
|
||
document.querySelectorAll('.days-options .day-btn').forEach(btn => {
|
||
if (btn.innerText.trim() === `${initialData_g.days}`) {
|
||
btn.classList.add('active');
|
||
}
|
||
});
|
||
|
||
// Массив людей теперь содержит поля запрещенных и любимых продуктов
|
||
console.log(initialData_g);
|
||
let people = initialData_g.users;
|
||
|
||
// --- 1. Рендеринг списка продуктов (Левая часть) ---
|
||
cartList = document.getElementById('cart-list');
|
||
scrollWrapper = document.getElementById('scroll-wrapper');
|
||
showMoreBtn = document.getElementById('show-more-btn');
|
||
remainingSpan = document.getElementById('remaining-count');
|
||
|
||
renderProducts();
|
||
|
||
// --- 2. Меню (Заменить и Удалить) ---
|
||
document.addEventListener('click', function(e) {
|
||
const menuBtn = e.target.closest('.menu-btn');
|
||
const menuDropdown = e.target.closest('.menu-dropdown');
|
||
const isReplace = e.target.closest('.menu-replace');
|
||
const isRemove = e.target.closest('.menu-remove');
|
||
const isClearAll = e.target.closest('.reorder-btn');
|
||
const isCloseModal = e.target.closest('.product-modal-overlay');
|
||
|
||
if(menuBtn) {
|
||
const dropdown = menuBtn.nextElementSibling;
|
||
const isOpen = dropdown.classList.contains('active');
|
||
document.querySelectorAll('.menu-dropdown.active').forEach(el => el.classList.remove('active'));
|
||
if(!isOpen) {
|
||
dropdown.classList.add('active');
|
||
}
|
||
e.stopPropagation();
|
||
} else if(!menuDropdown) {
|
||
document.querySelectorAll('.menu-dropdown.active').forEach(el => el.classList.remove('active'));
|
||
}
|
||
|
||
if(isReplace) {
|
||
const wrapper = isReplace.closest('.menu-btn-wrapper');
|
||
const li = wrapper.closest('.cart-item');
|
||
li.classList.add('replacing');
|
||
const index = Array.from(cartList.children).indexOf(li);
|
||
replaceProduct(allProducts[index].name).then(() => {
|
||
li.remove();
|
||
document.querySelectorAll('.menu-dropdown.active').forEach(el => el.classList.remove('active'));
|
||
allProducts.splice(index, 1);
|
||
visibleProducts = allProducts.slice(0, visibleProducts ? visibleProducts.length : 5);
|
||
renderProducts();
|
||
calculateListHeight();
|
||
});
|
||
}
|
||
|
||
if(isRemove) {
|
||
const wrapper = isRemove.closest('.menu-btn-wrapper');
|
||
const li = wrapper.closest('.cart-item');
|
||
li.classList.add('replacing');
|
||
const index = Array.from(cartList.children).indexOf(li);
|
||
deleteProduct(allProducts[index].name).then(() => {
|
||
li.remove();
|
||
document.querySelectorAll('.menu-dropdown.active').forEach(el => el.classList.remove('active'));
|
||
visibleProducts.splice(index, 1);
|
||
allProducts.splice(index, 1);
|
||
|
||
if(visibleProducts.length < allProducts.length) {
|
||
visibleProducts.push(allProducts[visibleProducts.length]);
|
||
}
|
||
renderProducts();
|
||
calculateListHeight();
|
||
})
|
||
}
|
||
|
||
if (isClearAll) {
|
||
requestWithRefresh(host + '/api/guest/clear_cookie', {method: 'POST'})
|
||
.then(r => {document.location.reload()});
|
||
}
|
||
|
||
if (isCloseModal) {
|
||
document.getElementById('modalProductOverlay').classList.remove('show');
|
||
}
|
||
});
|
||
|
||
showMoreBtn.addEventListener('click', () => {
|
||
while(visibleProducts.length < allProducts.length) {
|
||
visibleProducts.push(allProducts[visibleProducts.length]);
|
||
}
|
||
renderProducts();
|
||
scrollWrapper.style.maxHeight = '500px';
|
||
calculateListHeight();
|
||
});
|
||
|
||
// --- 3. Фиксированная высота ---
|
||
window.addEventListener('resize', calculateListHeight);
|
||
calculateListHeight();
|
||
|
||
// --- 4. Аккордеон (активна только одна вкладка) ---
|
||
document.querySelectorAll('.accordion-header').forEach(header => {
|
||
header.addEventListener('click', function() {
|
||
const item = this.closest('.accordion-item');
|
||
const isOpen = item.classList.contains('open');
|
||
document.querySelectorAll('.accordion-item').forEach(el => el.classList.remove('open'));
|
||
if(!isOpen) {
|
||
item.classList.add('open');
|
||
}
|
||
});
|
||
});
|
||
|
||
// --- 5. Дни ---
|
||
document.querySelectorAll('.day-btn').forEach(btn => {
|
||
btn.addEventListener('click', function() {
|
||
const parent = this.closest('.days-options');
|
||
parent.querySelectorAll('.day-btn').forEach(b => b.classList.remove('active'));
|
||
this.classList.add('active');
|
||
setOption('days', this.dataset.days);
|
||
document.querySelector('.summary-days').textContent = `${this.dataset.days} ${declension(this.dataset.days, ['день', 'дня', 'дней'])}`;
|
||
});
|
||
});
|
||
|
||
// --- 6. Семья с возможностью редактирования ---
|
||
const familyList = document.getElementById('family-list');
|
||
const familyDesc = document.getElementById('family-desc');
|
||
let editingIndex = null;
|
||
|
||
function renderPeople() {
|
||
familyList.innerHTML = cartPolicy.createHTML('');
|
||
people.forEach((person, index) => {
|
||
let avatar;
|
||
if (person.age < 16) {
|
||
avatar = '<img src="/images/broc-' +(person.gender === 'f' ? 'girl' : 'boy')+'.png" alt="ребёнок" />';
|
||
} else {
|
||
avatar = person.gender === 'f' ? '<img src="/images/broc-woman.png" alt="девушка" />' : '<img src="/images/broc-man.png" alt="парень" />';
|
||
}
|
||
const div = document.createElement('div');
|
||
div.className = 'family-member';
|
||
div.dataset.index = index;
|
||
div.innerHTML = cartPolicy.createHTML(`
|
||
<div class="avatar">${avatar}</div>
|
||
<div class="info">
|
||
<div class="name">${person.name}</div>
|
||
<div class="age">${person.age} лет</div>
|
||
</div>
|
||
<div class="delete-member" data-index="${index}">×</div>
|
||
`);
|
||
familyList.appendChild(div);
|
||
});
|
||
|
||
const count = people.length;
|
||
familyDesc.textContent = `${count} ${declension(count, ['человек', 'человека', 'человек'])}`;
|
||
if(count === 0) familyDesc.textContent = 'Не указаны';
|
||
|
||
document.querySelectorAll('.delete-member').forEach(btn => {
|
||
btn.addEventListener('click', function(e) {
|
||
e.stopPropagation();
|
||
const idx = parseInt(this.dataset.index);
|
||
people.splice(idx, 1);
|
||
renderPeople();
|
||
setOption('users', people);
|
||
});
|
||
});
|
||
}
|
||
renderPeople();
|
||
|
||
familyList.addEventListener('click', function(e) {
|
||
const member = e.target.closest('.family-member');
|
||
if (!member) return;
|
||
if (e.target.closest('.delete-member')) return;
|
||
const idx = parseInt(member.dataset.index);
|
||
openEditModal(idx);
|
||
});
|
||
|
||
// --- 7. Попап (Добавление и Редактирование) + Логика Тегов ---
|
||
const modal = document.getElementById('personModal');
|
||
const addBtn = document.getElementById('addMemberBtn');
|
||
const closeBtn = document.getElementById('closeModalBtn');
|
||
const saveBtn = document.getElementById('savePersonBtn');
|
||
const modalTitle = document.getElementById('modalTitle');
|
||
const genderBtns = document.querySelectorAll('.gender-btn');
|
||
|
||
const availableTags = initialData_g.available_groups;
|
||
|
||
function openEditModal(index = null) {
|
||
editingIndex = index;
|
||
|
||
// Очистка тегов внутри попапа
|
||
document.querySelectorAll('#personModal .tags-wrap').forEach(el => el.innerHTML = cartPolicy.createHTML(''));
|
||
|
||
if (editingIndex !== null) {
|
||
modalTitle.textContent = 'Редактировать человека';
|
||
const p = people[editingIndex];
|
||
document.getElementById('inputName').value = p.name;
|
||
document.getElementById('inputAge').value = p.age;
|
||
document.getElementById('inputWeight').value = p.weight;
|
||
document.getElementById('inputHeight').value = p.height;
|
||
genderBtns.forEach(b => {
|
||
b.classList.toggle('active', b.dataset.gender === p.gender);
|
||
});
|
||
|
||
// Рендерим сохраненные теги
|
||
if(p.avoid) p.avoid.forEach(tag => addTagToModal(tag, 'avoid', false));
|
||
if(p.favorite) p.favorite.forEach(tag => addTagToModal(tag, 'favorite', false));
|
||
} else {
|
||
modalTitle.textContent = 'Добавить человека';
|
||
document.getElementById('inputName').value = '';
|
||
document.getElementById('inputAge').value = '';
|
||
document.getElementById('inputWeight').value = '';
|
||
document.getElementById('inputHeight').value = '';
|
||
genderBtns.forEach(b => b.classList.remove('active'));
|
||
document.querySelector('.gender-btn[data-gender="m"]').classList.add('active');
|
||
}
|
||
modal.style.display = 'flex';
|
||
calculateListHeight();
|
||
}
|
||
|
||
addBtn.addEventListener('click', () => openEditModal(null));
|
||
|
||
function closeModal() { modal.style.display = 'none'; }
|
||
closeBtn.addEventListener('click', closeModal);
|
||
modal.addEventListener('click', function(e) {
|
||
if (e.target === this) closeModal();
|
||
});
|
||
|
||
genderBtns.forEach(btn => {
|
||
btn.addEventListener('click', function() {
|
||
genderBtns.forEach(b => b.classList.remove('active'));
|
||
this.classList.add('active');
|
||
});
|
||
});
|
||
|
||
// Логика добавления тега в попап
|
||
function addTagToModal(text, type, saveToPeople = true) {
|
||
const tagsWrap = document.querySelector(`#personModal .tags-wrap[data-target="${type}"]`);
|
||
|
||
// Проверка дубликата в своей группе
|
||
const existingInGroup = tagsWrap.querySelectorAll('.tag');
|
||
for(let t of existingInGroup) {
|
||
if(t.textContent.trim().replace('×','').trim() === text) return;
|
||
}
|
||
|
||
// Взаимоисключение: если тег есть в противоположной группе - удалить его оттуда
|
||
const oppositeType = type === 'avoid' ? 'favorite' : 'avoid';
|
||
const oppositeWrap = document.querySelector(`#personModal .tags-wrap[data-target="${oppositeType}"]`);
|
||
const oppositeTags = oppositeWrap.querySelectorAll('.tag');
|
||
for(let t of oppositeTags) {
|
||
if(t.textContent.trim().replace('×','').trim() === text) {
|
||
t.remove();
|
||
break;
|
||
}
|
||
}
|
||
|
||
const tag = document.createElement('div');
|
||
tag.className = `tag ${type === 'avoid' ? 'tag-red' : 'tag-green'}`;
|
||
tag.innerHTML = cartPolicy.createHTML(`${text} <span class="tag-close">×</span>`);
|
||
tag.querySelector('.tag-close').addEventListener('click', function() {
|
||
tag.remove();
|
||
});
|
||
tagsWrap.appendChild(tag);
|
||
}
|
||
|
||
// Автокомплит для полей в попапе
|
||
document.querySelectorAll('#personModal .pref-input').forEach(input => {
|
||
const type = input.dataset.type;
|
||
const listEl = document.querySelector(`#personModal .autocomplete-list[data-type="${type}"]`);
|
||
const tagsWrap = document.querySelector(`#personModal .tags-wrap[data-target="${type}"]`);
|
||
|
||
input.addEventListener('input', function() {
|
||
const val = this.value.toLowerCase();
|
||
listEl.innerHTML = cartPolicy.createHTML('');
|
||
|
||
// Ищем все уже выбранные теги в обеих группах внутри попапа
|
||
const allSelectedTags = new Set();
|
||
document.querySelectorAll('#personModal .tags-wrap .tag').forEach(tagEl => {
|
||
const tagText = tagEl.textContent.trim().replace('×', '').trim();
|
||
if(tagText) allSelectedTags.add(tagText);
|
||
});
|
||
|
||
if(val.length > 0) {
|
||
const matches = availableTags.filter(tag =>
|
||
tag.toLowerCase().includes(val) && !allSelectedTags.has(tag)
|
||
);
|
||
|
||
if(matches.length > 0) {
|
||
listEl.classList.add('active');
|
||
matches.forEach(match => {
|
||
const div = document.createElement('div');
|
||
div.textContent = match;
|
||
div.addEventListener('click', function() {
|
||
addTagToModal(match, type);
|
||
input.value = '';
|
||
listEl.classList.remove('active');
|
||
});
|
||
listEl.appendChild(div);
|
||
});
|
||
} else {
|
||
listEl.classList.remove('active');
|
||
}
|
||
} else {
|
||
listEl.classList.remove('active');
|
||
}
|
||
});
|
||
|
||
document.addEventListener('click', function(e) {
|
||
if(!input.contains(e.target) && !listEl.contains(e.target)) {
|
||
listEl.classList.remove('active');
|
||
}
|
||
});
|
||
});
|
||
|
||
// Сохранение пользователя (сбор тегов из DOM попапа)
|
||
saveBtn.addEventListener('click', () => {
|
||
const name = document.getElementById('inputName').value.trim();
|
||
const age = document.getElementById('inputAge').value.trim();
|
||
const weight = document.getElementById('inputWeight').value.trim();
|
||
const height = document.getElementById('inputHeight').value.trim();
|
||
const gender = document.querySelector('.gender-btn.active').dataset.gender;
|
||
|
||
if(!name) { alert('Пожалуйста, введите имя.'); return; }
|
||
if(!age || parseInt(age) < 7) { alert('Возраст должен быть от 7 лет.'); return; }
|
||
|
||
// Сбор тегов
|
||
const forbTags = [];
|
||
document.querySelector('#personModal .tags-wrap[data-target="avoid"]').querySelectorAll('.tag').forEach(el => {
|
||
forbTags.push(el.textContent.trim().replace('×', '').trim());
|
||
});
|
||
const favTags = [];
|
||
document.querySelector('#personModal .tags-wrap[data-target="favorite"]').querySelectorAll('.tag').forEach(el => {
|
||
favTags.push(el.textContent.trim().replace('×', '').trim());
|
||
});
|
||
|
||
const personData = { name, age, weight, height, gender, avoid: forbTags, favorite: favTags };
|
||
if (editingIndex !== null) {
|
||
people[editingIndex] = personData;
|
||
editingIndex = null;
|
||
} else {
|
||
people.push(personData);
|
||
}
|
||
renderPeople();
|
||
setOption('users', people);
|
||
closeModal();
|
||
});
|
||
|
||
// --- 8. Блок: Категории ---
|
||
const categories = initialData_g.available_groups;
|
||
const initialSelected = initialData_g.initial_groups;
|
||
let selectedCategories = [...initialSelected];
|
||
// let selectedCategories = [];
|
||
let isCategoriesExpanded = false;
|
||
const maxVisibleCategories = 7;
|
||
const sendUpdatedCategories = debounceBatch((categoriesNames) => {
|
||
let localCategories = [...selectedCategories]
|
||
categoriesNames.forEach((categoryName) => {
|
||
if (localCategories.includes(categoryName)) {
|
||
localCategories.splice(localCategories.indexOf(categoryName), 1);
|
||
} else {
|
||
localCategories.push(categoryName);
|
||
}
|
||
})
|
||
console.log('send', localCategories);
|
||
return setOption('categories', localCategories)
|
||
}, 1500);
|
||
|
||
|
||
const categoriesGrid = document.getElementById('categories-grid');
|
||
const prefsAccordionBlock = document.getElementById('prefs-accordion');
|
||
const prefsDescription = document.getElementById('prefs-desc');
|
||
|
||
function renderCategories() {
|
||
categoriesGrid.innerHTML = cartPolicy.createHTML('');
|
||
|
||
if (availableTags.length > 0) {
|
||
prefsAccordionBlock.classList.add('visible');
|
||
} else {
|
||
prefsAccordionBlock.classList.remove('visible');
|
||
}
|
||
|
||
if (selectedCategories.length > 0) {
|
||
document.getElementById('preferences-icon').classList.add('bg-green-light');
|
||
document.getElementById('preferences-icon').classList.remove('bg-gray-light');
|
||
if (selectedCategories.length === 1) {
|
||
prefsDescription.innerText = 'Выбрана 1 категория';
|
||
} else {
|
||
prefsDescription.innerText = 'Выбраны ' + selectedCategories.length + ' ' + declension(selectedCategories.length, ['категория', 'категории', 'категорий']);
|
||
}
|
||
} else {
|
||
document.getElementById('preferences-icon').classList.add('bg-gray-light');
|
||
document.getElementById('preferences-icon').classList.remove('bg-green-light');
|
||
prefsDescription.innerText = 'Не указаны';
|
||
}
|
||
const dataToShow = isCategoriesExpanded ? categories : (
|
||
(selectedCategories.length > 0 ? selectedCategories : categories).slice(0, maxVisibleCategories)
|
||
);
|
||
|
||
dataToShow.forEach(cat => {
|
||
const btn = document.createElement('button');
|
||
btn.className = `category-btn ${selectedCategories.includes(cat) ? 'active' : 'inactive'}`;
|
||
btn.innerHTML = cartPolicy.createHTML(`<span class="spacer-over">${cat}</span><span class="spacer-width">${cat}</span>`);
|
||
btn.dataset.category = cat;
|
||
btn.addEventListener('click', function() {
|
||
if (btn.classList.contains('loading-border')) {
|
||
return;
|
||
}
|
||
const catName = this.dataset.category;
|
||
btn.classList.add('loading-border');
|
||
sendUpdatedCategories(catName)
|
||
.finally(() => {
|
||
btn.classList.remove('loading-border');
|
||
});
|
||
});
|
||
categoriesGrid.appendChild(btn);
|
||
});
|
||
if (dataToShow.length > 0) {
|
||
const toggleBtn = document.createElement('button');
|
||
toggleBtn.className = 'toggle-categories-btn'
|
||
toggleBtn.id = 'expand-categories'
|
||
toggleBtn.innerHTML = cartPolicy.createHTML(
|
||
(!isCategoriesExpanded && dataToShow.length < selectedCategories.length ? '+' + (selectedCategories.length - dataToShow.length) : '') +
|
||
' <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"\n' +
|
||
' stroke-linejoin="round">\n' +
|
||
' <polyline points="18 15 12 9 6 15"></polyline>\n' +
|
||
' </svg>');
|
||
if (isCategoriesExpanded) {
|
||
toggleBtn.classList.remove('collapsed');
|
||
toggleBtn.classList.remove('show-more');
|
||
} else {
|
||
toggleBtn.classList.add('collapsed');
|
||
if (dataToShow.length < selectedCategories.length) {
|
||
toggleBtn.classList.add('show-more');
|
||
}
|
||
}
|
||
toggleBtn.addEventListener('click', function () {
|
||
isCategoriesExpanded = !isCategoriesExpanded;
|
||
renderCategories();
|
||
});
|
||
categoriesGrid.appendChild(toggleBtn);
|
||
}
|
||
}
|
||
|
||
|
||
renderCategories();
|
||
}
|
||
document.addEventListener('DOMContentLoaded', async () => {
|
||
wholeRender(await loadInitData());
|
||
});
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
const popup = document.getElementById('cookie-popup');
|
||
const acceptBtn = document.getElementById('cookie-accept');
|
||
|
||
// Проверяем, согласился ли пользователь ранее
|
||
if (!localStorage.getItem('cookie_accepted')) {
|
||
// Небольшая задержка для красоты появления
|
||
setTimeout(() => {
|
||
popup.classList.add('show');
|
||
}, 500);
|
||
}
|
||
|
||
// Обработчик нажатия на кнопку "Хорошо"
|
||
acceptBtn.addEventListener('click', function() {
|
||
// Сохраняем согласие в браузер
|
||
localStorage.setItem('cookie_accepted', 'true');
|
||
|
||
// Запускаем анимацию исчезновения
|
||
popup.classList.remove('show');
|
||
popup.classList.add('hide');
|
||
|
||
// Полностью удаляем из DOM после завершения анимации
|
||
setTimeout(() => {
|
||
popup.style.display = 'none';
|
||
}, 400);
|
||
});
|
||
|
||
|
||
document.getElementById('modalProductOverlay').addEventListener('click', function(e) {
|
||
if (e.target === this) {
|
||
this.classList.remove('active');
|
||
}
|
||
});
|
||
});
|
||
function openModal(imageSrc, name, quantity, price, onReplace, onAnother) {
|
||
// Получаем элементы по новым id
|
||
const overlay = document.getElementById('modalProductOverlay');
|
||
const img = document.getElementById('modalProductImage');
|
||
const title = document.getElementById('modalProductTitle');
|
||
const qtySpan = document.getElementById('modalProductQuantity');
|
||
const priceSpan = document.getElementById('modalProductPrice');
|
||
const replaceBtn = document.getElementById('modalProductReplaceBtn');
|
||
const anotherBtn = document.getElementById('modalProductAnotherBtn');
|
||
|
||
// Заполняем данными
|
||
img.src = imageSrc || '';
|
||
img.alt = name || 'Товар';
|
||
title.textContent = name || 'Без названия';
|
||
qtySpan.textContent = quantity !== undefined ? quantity : '—';
|
||
priceSpan.textContent = new Intl.NumberFormat("ru-RU", { style: "currency", currency: "RUB" }).format(
|
||
Math.round(price * 100) / 100,
|
||
);
|
||
|
||
// Удаляем старые обработчики, если они были (храним в свойствах кнопок)
|
||
if (replaceBtn._listener) {
|
||
replaceBtn.removeEventListener('click', replaceBtn._listener);
|
||
delete replaceBtn._listener;
|
||
}
|
||
if (anotherBtn._listener) {
|
||
anotherBtn.removeEventListener('click', anotherBtn._listener);
|
||
delete anotherBtn._listener;
|
||
}
|
||
|
||
// Создаём новые обработчики, которые вызывают переданные колбэки
|
||
const replaceHandler = function() {
|
||
if (typeof onReplace === 'function') onReplace();
|
||
};
|
||
const anotherHandler = function() {
|
||
if (typeof onAnother === 'function') onAnother();
|
||
};
|
||
|
||
// Сохраняем ссылки и добавляем слушатели
|
||
replaceBtn._listener = replaceHandler;
|
||
anotherBtn._listener = anotherHandler;
|
||
replaceBtn.addEventListener('click', replaceHandler);
|
||
anotherBtn.addEventListener('click', anotherHandler);
|
||
|
||
// Показываем модалку
|
||
overlay.classList.add('show');
|
||
} |