Корзина в телеграм боте с WebApp
Пишу телеграм бот доставки продуктов на python с aiogram 3.
Чтобы бот был чуть более уникальным я решил использовать относительно новую фишку телеграмма с WebApp
, то есть каталоги с продуктам выглядят как полноценные окна в настоящем приложении. Для создания окон каталогов я использую html(css)
и JavaScript
. У меня уже реализована окно с продуктами, регулирование их количества, а также через JS
информация успешно передается в бот, то есть бот сразу дает список выбранных продуктов через метод web_app
.
Однако у меня появились сложности с созданием полноценной корзины, чтобы бот запоминал все выбранные продукты, чтобы в него можно было добавлять новые, а также очищать всю корзину (желательно чтоб каждый товар в корзине можно было отдельно удалить). Можно без базы данных, так как это чисто шаблон по сути. Так что очень прошу помощи с реализацией корзины, сильно застопорился на этом моменте, что тут можно придумать. Также в видео, прикрепленном ниже, можете увидеть как всё работает.
Python
скрипт main
с методом web_app
, который выдает список выбранных продуктов:
@dp.message()
async def web_app(callback_query):
json_data = callback_query.web_app_data.data
parsed_data = json.loads(json_data)
message = ""
for item in parsed_data['items']:
product_name = item['name']
price = item['price']
message += f"Продукт: {product_name}\n"
message += f"Стоимость: {price}\n\n"
message += f"Общая стоимость: {parsed_data['totalPrice']}"
await bot.send_message(callback_query.from_user.id, f"""
{message}
""")
JavaScript
и `HTML со всеми основными функциями каталога:
let tg = window.Telegram.WebApp;
tg.expand();
tg.MainButton.textColor = '#FFFFFF';
tg.MainButton.color = '#2cab37';
let items = {
item1: { id: "item1", price: 80, quantity: 0, name: "Молоко коровка из кореновки 2,5%" },
item2: { id: "item2", price: 120, quantity: 0, name: "Масло сливочное кубанский молочник 82,5%" },
item3: { id: "item3", price: 70, quantity: 0, name: "Творог коровка из кореновки 9%" },
item4: { id: "item4", price: 47, quantity: 0, name: "Пломбир коровка из кореновки" },
item5: { id: "item5", price: 100, quantity: 0, name: "Кефир коровка из кореновки 2,5%" },
item6: { id: "item6", price: 150, quantity: 0, name: "Ряженка коровка из кореновки 2,5%" },
item7: { id: "item7", price: 110, quantity: 0, name: "Йогурт коровка из кореновки" },
item8: { id: "item8", price: 70, quantity: 0, name: "Сгущенка коровка из кореновки 8,5%" }
};
function updateQuantity(itemId, change) {
let item = items[itemId];
item.quantity += change;
if (item.quantity < 0) item.quantity = 0;
if (item.quantity > 10) item.quantity = 10;
document.getElementById("qty" + itemId.slice(-1)).innerText = item.quantity;
toggleItem(itemId);
}
function toggleItem(itemId) {
let item = items[itemId];
let btn = document.getElementById("add" + itemId.slice(-1));
let subtractBtn = document.getElementById("subtract" + itemId.slice(-1));
btn.classList.remove('added-to-cart');
btn.style.display = 'inline-block';
subtractBtn.style.display = 'inline-block';
let totalPrice = calculateTotalPrice();
if (totalPrice > 0) {
tg.MainButton.setText(`Общая цена товаров: ${totalPrice}`);
if (!tg.MainButton.isVisible) {
tg.MainButton.show();
}
} else {
tg.MainButton.hide();
}
}
function openModal(element) {
var productName = element.parentNode.querySelector('p').textContent;
document.getElementById('product-name').textContent = productName;
document.getElementById('my-modal').style.display = 'block';
}
function closeModal() {
document.getElementById('my-modal').style.display = 'none';
}
document.getElementById("open-modal-btn").addEventListener("click", function() {
document.getElementById("my-modal").classList.add("open")
})
document.getElementById("close-my-modal-btn").addEventListener("click", function() {
document.getElementById("my-modal").classList.remove("open")
})
Telegram.WebApp.onEvent("mainButtonClicked", function() {
let data = {
items: Object.values(items).filter(item => item.quantity > 0),
totalPrice: calculateTotalPrice()
};
tg.sendData(JSON.stringify(data));
});
function calculateTotalPrice() {
return Object.values(items).reduce((total, item) => total + (item.price *
item.quantity), 0);
}
document.getElementById("add1").addEventListener("click", function() {
updateQuantity("item1", 1);
});
document.getElementById("subtract1").addEventListener("click", function() {
updateQuantity("item1", -1);
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="style.css">
<title>Document</title>
</head>
<body>
<h1>Молочные продукты</h1>
<div class="center">
<div class="container">
<div class="inner">
<div class="item" id="item1">
<img src="image/11.png" alt="" class="img" id="open-modal-btn" onclick="openModal(this)">
<p>Молоко коровка из кореновки 2,5%</p>
<p>80 ₽</p>
<div class="btn-container">
<button class="btn" id="add1">+</button>
<span id="qty1">0</span>
<button class="btn" id="subtract1">-</button>
</div>
</div>
<div class="modal" id="my-modal">
<div class="modal_box">
<button class="modal_close-btn" id="close-my-modal-btn" onclick="closeModal()">
<svg width="23" height="25" viewBox="0 0 23 25" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2.09082 0.03125L22.9999 22.0294L20.909 24.2292L-8.73579e-05 2.23106L2.09082 0.03125Z" fill="#333333"/>
<path d="M0 22.0295L20.9091 0.0314368L23 2.23125L2.09091 24.2294L0 22.0295Z" fill="#333333"/>
</svg>
</button>
<img src="image/11.png" alt="" class="img">
<h2>Молоко коровка из кореновки 2,5%</h2>
<p class="left"><span class="grey">Состав</span><br>
Цельное молоко, обезжиренное молоко<br>
<span class="grey">Количество</span><br>
900 мл<br>
<span class="grey">Цена</span><br>
80 ₽<br>
<span class="grey">Пищевая ценность на 100 г</span><br>
Белки: 3.0 г Жиры: 2,5 г Углеводы: 4,7 Калории: 55.0 ккал<br>
<span class="grey">Срок годности</span><br>
9 суток при температуре (4±2)°C
</p>
</div>
</div>
</div>
</div>
</div>
<script src="https://telegram.org/js/telegram-web-app.js"></script>
<script src="app.js"></script>
</body>
</html>