"Fix-BUTTON_DATA_INVALID-and-add-multi-buy-buttons"
This commit is contained in:
parent
c961dfa47a
commit
694ce15549
@ -29,6 +29,8 @@ namespace TeleBot.Handlers
|
||||
private readonly IBotActivityTracker _activityTracker;
|
||||
private readonly IConfiguration _configuration;
|
||||
private readonly ILogger<CallbackHandler> _logger;
|
||||
private readonly MenuBuilder _menuBuilder;
|
||||
private readonly CallbackDataMapper _mapper;
|
||||
|
||||
public CallbackHandler(
|
||||
ISessionManager sessionManager,
|
||||
@ -37,7 +39,9 @@ namespace TeleBot.Handlers
|
||||
IProductCarouselService carouselService,
|
||||
IBotActivityTracker activityTracker,
|
||||
IConfiguration configuration,
|
||||
ILogger<CallbackHandler> logger)
|
||||
ILogger<CallbackHandler> logger,
|
||||
MenuBuilder menuBuilder,
|
||||
CallbackDataMapper mapper)
|
||||
{
|
||||
_sessionManager = sessionManager;
|
||||
_shopService = shopService;
|
||||
@ -46,6 +50,8 @@ namespace TeleBot.Handlers
|
||||
_activityTracker = activityTracker;
|
||||
_configuration = configuration;
|
||||
_logger = logger;
|
||||
_menuBuilder = menuBuilder;
|
||||
_mapper = mapper;
|
||||
}
|
||||
|
||||
public async Task HandleCallbackAsync(ITelegramBotClient bot, CallbackQuery callbackQuery)
|
||||
@ -115,7 +121,11 @@ namespace TeleBot.Handlers
|
||||
break;
|
||||
|
||||
case "remove":
|
||||
await HandleRemoveFromCart(bot, callbackQuery, session, Guid.Parse(data[1]));
|
||||
{
|
||||
var (_, productId, _, _) = _mapper.ParseCallback(callbackQuery.Data);
|
||||
if (productId.HasValue)
|
||||
await HandleRemoveFromCart(bot, callbackQuery, session, productId.Value);
|
||||
}
|
||||
break;
|
||||
|
||||
case "clear_cart":
|
||||
@ -372,32 +382,40 @@ namespace TeleBot.Handlers
|
||||
|
||||
private async Task HandleQuantityChange(ITelegramBotClient bot, Message message, UserSession session, string[] data)
|
||||
{
|
||||
// Format: qty:productId:newQuantity
|
||||
var productId = Guid.Parse(data[1]);
|
||||
var quantity = int.Parse(data[2]);
|
||||
// Parse callback data using mapper
|
||||
var (_, productId, quantity, _) = _mapper.ParseCallback(string.Join(":", data));
|
||||
|
||||
var product = await _shopService.GetProductAsync(productId);
|
||||
if (!productId.HasValue || !quantity.HasValue)
|
||||
return;
|
||||
|
||||
var product = await _shopService.GetProductAsync(productId.Value);
|
||||
if (product == null)
|
||||
return;
|
||||
|
||||
session.TempData["current_quantity"] = quantity;
|
||||
session.TempData["current_quantity"] = quantity.Value;
|
||||
|
||||
await bot.EditMessageReplyMarkupAsync(
|
||||
message.Chat.Id,
|
||||
message.MessageId,
|
||||
MenuBuilder.ProductDetailMenu(product, quantity)
|
||||
_menuBuilder.ProductDetailMenu(product, quantity.Value)
|
||||
);
|
||||
}
|
||||
|
||||
private async Task HandleAddToCart(ITelegramBotClient bot, CallbackQuery callbackQuery, UserSession session, string[] data)
|
||||
{
|
||||
// Format: add:productId:quantity or add:productId:quantity:multiBuyId or add:productId:quantity:multiBuyId:variant
|
||||
var productId = Guid.Parse(data[1]);
|
||||
var quantity = int.Parse(data[2]);
|
||||
Guid? multiBuyId = data.Length > 3 && !data[3].Contains(":") ? Guid.Parse(data[3]) : null;
|
||||
string? selectedVariant = data.Length > 4 ? data[4] : (data.Length > 3 && data[3].Contains(":") ? data[3] : null);
|
||||
// Parse callback data using mapper
|
||||
var (_, productId, quantity, multiBuyId) = _mapper.ParseCallback(string.Join(":", data));
|
||||
|
||||
var product = await _shopService.GetProductAsync(productId);
|
||||
if (!productId.HasValue || !quantity.HasValue)
|
||||
{
|
||||
await bot.AnswerCallbackQueryAsync(callbackQuery.Id, "Invalid product data", showAlert: true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for variant in data (old format compatibility)
|
||||
string? selectedVariant = data.Length > 4 ? data[4] : null;
|
||||
|
||||
var product = await _shopService.GetProductAsync(productId.Value);
|
||||
if (product == null)
|
||||
{
|
||||
await bot.AnswerCallbackQueryAsync(callbackQuery.Id, "Product not found", showAlert: true);
|
||||
@ -407,13 +425,15 @@ namespace TeleBot.Handlers
|
||||
// If product has variants but none selected, show variant selection
|
||||
if (selectedVariant == null && product.Variants?.Any() == true)
|
||||
{
|
||||
await ShowVariantSelection(bot, callbackQuery.Message!, session, product, quantity, multiBuyId);
|
||||
await ShowVariantSelection(bot, callbackQuery.Message!, session, product, quantity.Value, multiBuyId);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get price based on multi-buy or base product
|
||||
decimal price = product.Price;
|
||||
string itemName = product.Name;
|
||||
int finalQuantity = quantity.Value;
|
||||
|
||||
if (multiBuyId.HasValue && product.MultiBuys != null)
|
||||
{
|
||||
var multiBuy = product.MultiBuys.FirstOrDefault(mb => mb.Id == multiBuyId);
|
||||
@ -421,7 +441,7 @@ namespace TeleBot.Handlers
|
||||
{
|
||||
price = multiBuy.Price;
|
||||
itemName = $"{product.Name} ({multiBuy.Name})";
|
||||
quantity = multiBuy.Quantity; // Use multi-buy quantity
|
||||
finalQuantity = multiBuy.Quantity; // Use multi-buy quantity
|
||||
}
|
||||
}
|
||||
|
||||
@ -431,7 +451,7 @@ namespace TeleBot.Handlers
|
||||
itemName += $" - {selectedVariant}";
|
||||
}
|
||||
|
||||
session.Cart.AddItem(productId, itemName, price, quantity, multiBuyId, selectedVariant);
|
||||
session.Cart.AddItem(productId.Value, itemName, price, finalQuantity, multiBuyId, selectedVariant);
|
||||
|
||||
// Track add to cart action
|
||||
await _activityTracker.TrackActivityAsync(
|
||||
@ -439,13 +459,13 @@ namespace TeleBot.Handlers
|
||||
ActivityTypes.AddToCart,
|
||||
$"Added to cart: {itemName}",
|
||||
product,
|
||||
price * quantity,
|
||||
quantity
|
||||
price * finalQuantity,
|
||||
finalQuantity
|
||||
);
|
||||
|
||||
await bot.AnswerCallbackQueryAsync(
|
||||
callbackQuery.Id,
|
||||
$"✅ Added {quantity}x {itemName} to cart",
|
||||
$"✅ Added {finalQuantity}x {itemName} to cart",
|
||||
showAlert: false
|
||||
);
|
||||
|
||||
@ -469,7 +489,7 @@ namespace TeleBot.Handlers
|
||||
message.MessageId,
|
||||
MessageFormatter.FormatCart(session.Cart),
|
||||
parseMode: Telegram.Bot.Types.Enums.ParseMode.Markdown,
|
||||
replyMarkup: MenuBuilder.CartMenu(session.Cart)
|
||||
replyMarkup: _menuBuilder.CartMenu(session.Cart)
|
||||
);
|
||||
session.State = SessionState.ViewingCart;
|
||||
}
|
||||
@ -480,7 +500,7 @@ namespace TeleBot.Handlers
|
||||
chatId,
|
||||
MessageFormatter.FormatCart(session.Cart),
|
||||
parseMode: Telegram.Bot.Types.Enums.ParseMode.Markdown,
|
||||
replyMarkup: MenuBuilder.CartMenu(session.Cart)
|
||||
replyMarkup: _menuBuilder.CartMenu(session.Cart)
|
||||
);
|
||||
session.State = SessionState.ViewingCart;
|
||||
}
|
||||
@ -565,7 +585,7 @@ namespace TeleBot.Handlers
|
||||
callbackQuery.Message!.Chat.Id,
|
||||
MessageFormatter.FormatCart(session.Cart),
|
||||
parseMode: Telegram.Bot.Types.Enums.ParseMode.Markdown,
|
||||
replyMarkup: MenuBuilder.CartMenu(session.Cart)
|
||||
replyMarkup: _menuBuilder.CartMenu(session.Cart)
|
||||
);
|
||||
|
||||
// Immediately proceed to checkout
|
||||
@ -634,7 +654,7 @@ namespace TeleBot.Handlers
|
||||
callbackQuery.Message!.Chat.Id,
|
||||
MessageFormatter.FormatCart(session.Cart),
|
||||
parseMode: Telegram.Bot.Types.Enums.ParseMode.Markdown,
|
||||
replyMarkup: MenuBuilder.CartMenu(session.Cart)
|
||||
replyMarkup: _menuBuilder.CartMenu(session.Cart)
|
||||
);
|
||||
|
||||
// Immediately proceed to checkout
|
||||
@ -738,7 +758,7 @@ namespace TeleBot.Handlers
|
||||
message.Chat.Id,
|
||||
message.MessageId,
|
||||
"❌ Failed to create order. Please try again.",
|
||||
replyMarkup: MenuBuilder.CartMenu(session.Cart)
|
||||
replyMarkup: _menuBuilder.CartMenu(session.Cart)
|
||||
);
|
||||
return;
|
||||
}
|
||||
@ -823,7 +843,7 @@ namespace TeleBot.Handlers
|
||||
$"• Network connectivity issues\n\n" +
|
||||
$"Your cart has been restored. Please try again.",
|
||||
Telegram.Bot.Types.Enums.ParseMode.Markdown,
|
||||
MenuBuilder.CartMenu(session.Cart)
|
||||
_menuBuilder.CartMenu(session.Cart)
|
||||
);
|
||||
return;
|
||||
}
|
||||
@ -863,7 +883,7 @@ namespace TeleBot.Handlers
|
||||
$"Our payment system may be undergoing maintenance.\n" +
|
||||
$"Your cart has been restored. Please try again later.",
|
||||
Telegram.Bot.Types.Enums.ParseMode.Markdown,
|
||||
MenuBuilder.CartMenu(session.Cart)
|
||||
_menuBuilder.CartMenu(session.Cart)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -20,19 +20,22 @@ namespace TeleBot.Handlers
|
||||
private readonly IPrivacyService _privacyService;
|
||||
private readonly IProductCarouselService _carouselService;
|
||||
private readonly ILogger<CommandHandler> _logger;
|
||||
private readonly MenuBuilder _menuBuilder;
|
||||
|
||||
public CommandHandler(
|
||||
ISessionManager sessionManager,
|
||||
ILittleShopService shopService,
|
||||
IPrivacyService privacyService,
|
||||
IProductCarouselService carouselService,
|
||||
ILogger<CommandHandler> logger)
|
||||
ILogger<CommandHandler> logger,
|
||||
MenuBuilder menuBuilder)
|
||||
{
|
||||
_sessionManager = sessionManager;
|
||||
_shopService = shopService;
|
||||
_privacyService = privacyService;
|
||||
_carouselService = carouselService;
|
||||
_logger = logger;
|
||||
_menuBuilder = menuBuilder;
|
||||
}
|
||||
|
||||
public async Task HandleCommandAsync(ITelegramBotClient bot, Message message, string command, string? args)
|
||||
@ -202,7 +205,7 @@ namespace TeleBot.Handlers
|
||||
message.Chat.Id,
|
||||
text,
|
||||
parseMode: Telegram.Bot.Types.Enums.ParseMode.Markdown,
|
||||
replyMarkup: MenuBuilder.CartMenu(session.Cart)
|
||||
replyMarkup: _menuBuilder.CartMenu(session.Cart)
|
||||
);
|
||||
|
||||
session.State = Models.SessionState.ViewingCart;
|
||||
|
||||
@ -16,6 +16,7 @@ using TeleBot;
|
||||
using TeleBot.Handlers;
|
||||
using TeleBot.Services;
|
||||
using TeleBot.Http;
|
||||
using TeleBot.UI;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
var BrandName = "Little Shop";
|
||||
@ -90,6 +91,10 @@ builder.Services.AddSingleton<ICommandHandler, CommandHandler>();
|
||||
builder.Services.AddSingleton<ICallbackHandler, CallbackHandler>();
|
||||
builder.Services.AddSingleton<IMessageHandler, MessageHandler>();
|
||||
|
||||
// Callback Data Mapper (for short IDs to avoid Telegram's 64-byte limit)
|
||||
builder.Services.AddSingleton<CallbackDataMapper>();
|
||||
builder.Services.AddSingleton<MenuBuilder>();
|
||||
|
||||
// Bot Manager Service (for registration and metrics) - Single instance with direct connection (internal API)
|
||||
builder.Services.AddHttpClient<BotManagerService>()
|
||||
.ConfigurePrimaryHttpMessageHandler(sp =>
|
||||
|
||||
100
TeleBot/TeleBot/Services/CallbackDataMapper.cs
Normal file
100
TeleBot/TeleBot/Services/CallbackDataMapper.cs
Normal file
@ -0,0 +1,100 @@
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace TeleBot.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Maps long GUIDs to short IDs for Telegram callback data (64-byte limit)
|
||||
/// </summary>
|
||||
public class CallbackDataMapper
|
||||
{
|
||||
private readonly ConcurrentDictionary<string, Guid> _shortToGuid = new();
|
||||
private readonly ConcurrentDictionary<Guid, string> _guidToShort = new();
|
||||
private int _nextId = 1;
|
||||
private readonly object _lock = new();
|
||||
|
||||
/// <summary>
|
||||
/// Get or create a short ID for a GUID
|
||||
/// </summary>
|
||||
public string GetShortId(Guid guid, string prefix = "id")
|
||||
{
|
||||
if (_guidToShort.TryGetValue(guid, out var existing))
|
||||
return existing;
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
// Double-check after acquiring lock
|
||||
if (_guidToShort.TryGetValue(guid, out existing))
|
||||
return existing;
|
||||
|
||||
var shortId = $"{prefix}{_nextId++}";
|
||||
_shortToGuid[shortId] = guid;
|
||||
_guidToShort[guid] = shortId;
|
||||
return shortId;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decode a short ID back to GUID
|
||||
/// </summary>
|
||||
public Guid? DecodeShortId(string shortId)
|
||||
{
|
||||
return _shortToGuid.TryGetValue(shortId, out var guid) ? guid : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Build callback data with short IDs
|
||||
/// Format: action:shortProductId[:quantity[:shortMultiBuyId]]
|
||||
/// </summary>
|
||||
public string BuildCallback(string action, Guid productId, int? quantity = null, Guid? multiBuyId = null)
|
||||
{
|
||||
var parts = new List<string> { action, GetShortId(productId, "p") };
|
||||
|
||||
if (quantity.HasValue)
|
||||
parts.Add(quantity.Value.ToString());
|
||||
|
||||
if (multiBuyId.HasValue)
|
||||
parts.Add(GetShortId(multiBuyId.Value, "mb"));
|
||||
|
||||
var result = string.Join(":", parts);
|
||||
|
||||
// Ensure we don't exceed Telegram's 64-byte limit
|
||||
if (result.Length > 63)
|
||||
throw new InvalidOperationException($"Callback data too long ({result.Length} bytes): {result}");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse callback data with short IDs
|
||||
/// </summary>
|
||||
public (string action, Guid? productId, int? quantity, Guid? multiBuyId) ParseCallback(string callbackData)
|
||||
{
|
||||
var parts = callbackData.Split(':');
|
||||
var action = parts[0];
|
||||
|
||||
Guid? productId = null;
|
||||
int? quantity = null;
|
||||
Guid? multiBuyId = null;
|
||||
|
||||
if (parts.Length > 1)
|
||||
productId = DecodeShortId(parts[1]);
|
||||
|
||||
if (parts.Length > 2 && int.TryParse(parts[2], out var qty))
|
||||
quantity = qty;
|
||||
|
||||
if (parts.Length > 3)
|
||||
multiBuyId = DecodeShortId(parts[3]);
|
||||
|
||||
return (action, productId, quantity, multiBuyId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear old mappings (call periodically to prevent memory buildup)
|
||||
/// </summary>
|
||||
public void ClearMappings()
|
||||
{
|
||||
_shortToGuid.Clear();
|
||||
_guidToShort.Clear();
|
||||
_nextId = 1;
|
||||
}
|
||||
}
|
||||
@ -29,15 +29,18 @@ namespace TeleBot.Services
|
||||
private readonly IConfiguration _configuration;
|
||||
private readonly ILogger<ProductCarouselService> _logger;
|
||||
private readonly HttpClient _httpClient;
|
||||
private readonly MenuBuilder _menuBuilder;
|
||||
private readonly string _imageCachePath;
|
||||
|
||||
public ProductCarouselService(
|
||||
IConfiguration configuration,
|
||||
ILogger<ProductCarouselService> logger,
|
||||
HttpClient httpClient)
|
||||
HttpClient httpClient,
|
||||
MenuBuilder menuBuilder)
|
||||
{
|
||||
_configuration = configuration;
|
||||
_logger = logger;
|
||||
_menuBuilder = menuBuilder;
|
||||
_httpClient = httpClient;
|
||||
_imageCachePath = Path.Combine(Environment.CurrentDirectory, "image_cache");
|
||||
|
||||
@ -208,7 +211,7 @@ namespace TeleBot.Services
|
||||
image,
|
||||
caption: FormatProductCaption(product),
|
||||
parseMode: Telegram.Bot.Types.Enums.ParseMode.Markdown,
|
||||
replyMarkup: MenuBuilder.ProductDetailMenu(product)
|
||||
replyMarkup: _menuBuilder.ProductDetailMenu(product)
|
||||
);
|
||||
}
|
||||
else
|
||||
@ -218,7 +221,7 @@ namespace TeleBot.Services
|
||||
chatId,
|
||||
MessageFormatter.FormatProductDetail(product),
|
||||
parseMode: Telegram.Bot.Types.Enums.ParseMode.Markdown,
|
||||
replyMarkup: MenuBuilder.ProductDetailMenu(product)
|
||||
replyMarkup: _menuBuilder.ProductDetailMenu(product)
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -231,7 +234,7 @@ namespace TeleBot.Services
|
||||
chatId,
|
||||
MessageFormatter.FormatProductDetail(product),
|
||||
parseMode: Telegram.Bot.Types.Enums.ParseMode.Markdown,
|
||||
replyMarkup: MenuBuilder.ProductDetailMenu(product)
|
||||
replyMarkup: _menuBuilder.ProductDetailMenu(product)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -20,8 +20,10 @@ namespace TeleBot
|
||||
var config = new ConfigurationBuilder().Build();
|
||||
var logger = NullLogger<ProductCarouselService>.Instance;
|
||||
var httpClient = new System.Net.Http.HttpClient();
|
||||
var mapper = new TeleBot.Services.CallbackDataMapper();
|
||||
var menuBuilder = new TeleBot.UI.MenuBuilder(mapper);
|
||||
|
||||
var carouselService = new ProductCarouselService(config, logger, httpClient);
|
||||
var carouselService = new ProductCarouselService(config, logger, httpClient, menuBuilder);
|
||||
|
||||
// Test image URL validation
|
||||
var validUrls = new[]
|
||||
@ -43,8 +45,10 @@ namespace TeleBot
|
||||
var config = new ConfigurationBuilder().Build();
|
||||
var logger = NullLogger<ProductCarouselService>.Instance;
|
||||
var httpClient = new System.Net.Http.HttpClient();
|
||||
var mapper = new TeleBot.Services.CallbackDataMapper();
|
||||
var menuBuilder = new TeleBot.UI.MenuBuilder(mapper);
|
||||
|
||||
var carouselService = new ProductCarouselService(config, logger, httpClient);
|
||||
var carouselService = new ProductCarouselService(config, logger, httpClient, menuBuilder);
|
||||
|
||||
// Create a test product with image
|
||||
var testProduct = new Product
|
||||
|
||||
@ -4,11 +4,18 @@ using System.Linq;
|
||||
using LittleShop.Client.Models;
|
||||
using Telegram.Bot.Types.ReplyMarkups;
|
||||
using TeleBot.Models;
|
||||
using TeleBot.Services;
|
||||
|
||||
namespace TeleBot.UI
|
||||
{
|
||||
public static class MenuBuilder
|
||||
public class MenuBuilder
|
||||
{
|
||||
private readonly CallbackDataMapper _mapper;
|
||||
|
||||
public MenuBuilder(CallbackDataMapper mapper)
|
||||
{
|
||||
_mapper = mapper;
|
||||
}
|
||||
public static InlineKeyboardMarkup MainMenu()
|
||||
{
|
||||
return new InlineKeyboardMarkup(new[]
|
||||
@ -90,7 +97,7 @@ namespace TeleBot.UI
|
||||
return new InlineKeyboardMarkup(buttons);
|
||||
}
|
||||
|
||||
public static InlineKeyboardMarkup ProductDetailMenu(Product product, int quantity = 1)
|
||||
public InlineKeyboardMarkup ProductDetailMenu(Product product, int quantity = 1)
|
||||
{
|
||||
var buttons = new List<InlineKeyboardButton[]>();
|
||||
|
||||
@ -106,14 +113,14 @@ namespace TeleBot.UI
|
||||
|
||||
foreach (var multiBuy in product.MultiBuys.Where(mb => mb.IsActive).OrderBy(mb => mb.Quantity))
|
||||
{
|
||||
var label = $"{multiBuy.Name} - ${multiBuy.Price:F2}";
|
||||
var label = $"{multiBuy.Name} - £{multiBuy.Price:F2}";
|
||||
if (multiBuy.Quantity > 1)
|
||||
label += $" (${multiBuy.PricePerUnit:F2}/each)";
|
||||
label += $" (£{multiBuy.PricePerUnit:F2}/each)";
|
||||
|
||||
// If has variants, need variant selection first
|
||||
// Use short callback data
|
||||
var callbackData = hasVariants
|
||||
? $"selectvar:{product.Id}:{multiBuy.Quantity}:{multiBuy.Id}"
|
||||
: $"add:{product.Id}:{multiBuy.Quantity}:{multiBuy.Id}";
|
||||
? _mapper.BuildCallback("selectvar", product.Id, multiBuy.Quantity, multiBuy.Id)
|
||||
: _mapper.BuildCallback("add", product.Id, multiBuy.Quantity, multiBuy.Id);
|
||||
|
||||
buttons.Add(new[]
|
||||
{
|
||||
@ -123,12 +130,12 @@ namespace TeleBot.UI
|
||||
|
||||
// Add regular single item option
|
||||
var singleCallbackData = hasVariants
|
||||
? $"selectvar:{product.Id}:1"
|
||||
: $"add:{product.Id}:1";
|
||||
? _mapper.BuildCallback("selectvar", product.Id, 1)
|
||||
: _mapper.BuildCallback("add", product.Id, 1);
|
||||
|
||||
buttons.Add(new[] {
|
||||
InlineKeyboardButton.WithCallbackData(
|
||||
$"🛒 Single Item - ${product.Price:F2}",
|
||||
$"🛒 Single Item - £{product.Price:F2}",
|
||||
singleCallbackData
|
||||
)
|
||||
});
|
||||
@ -138,21 +145,21 @@ namespace TeleBot.UI
|
||||
// No multi-buys, show quantity selector
|
||||
var quantityButtons = new List<InlineKeyboardButton>();
|
||||
if (quantity > 1)
|
||||
quantityButtons.Add(InlineKeyboardButton.WithCallbackData("➖", $"qty:{product.Id}:{quantity - 1}"));
|
||||
quantityButtons.Add(InlineKeyboardButton.WithCallbackData("➖", _mapper.BuildCallback("qty", product.Id, quantity - 1)));
|
||||
quantityButtons.Add(InlineKeyboardButton.WithCallbackData($"Qty: {quantity}", "noop"));
|
||||
if (quantity < 10)
|
||||
quantityButtons.Add(InlineKeyboardButton.WithCallbackData("➕", $"qty:{product.Id}:{quantity + 1}"));
|
||||
quantityButtons.Add(InlineKeyboardButton.WithCallbackData("➕", _mapper.BuildCallback("qty", product.Id, quantity + 1)));
|
||||
|
||||
buttons.Add(quantityButtons.ToArray());
|
||||
|
||||
// Add to cart button
|
||||
var addCallbackData = hasVariants
|
||||
? $"selectvar:{product.Id}:{quantity}"
|
||||
: $"add:{product.Id}:{quantity}";
|
||||
? _mapper.BuildCallback("selectvar", product.Id, quantity)
|
||||
: _mapper.BuildCallback("add", product.Id, quantity);
|
||||
|
||||
buttons.Add(new[] {
|
||||
InlineKeyboardButton.WithCallbackData(
|
||||
$"🛒 Add to Cart - ${product.Price * quantity:F2}",
|
||||
$"🛒 Add to Cart - £{product.Price * quantity:F2}",
|
||||
addCallbackData
|
||||
)
|
||||
});
|
||||
@ -184,7 +191,7 @@ namespace TeleBot.UI
|
||||
return new InlineKeyboardMarkup(buttons);
|
||||
}
|
||||
|
||||
public static InlineKeyboardMarkup CartMenu(ShoppingCart cart)
|
||||
public InlineKeyboardMarkup CartMenu(ShoppingCart cart)
|
||||
{
|
||||
var buttons = new List<InlineKeyboardButton[]>();
|
||||
|
||||
@ -196,7 +203,7 @@ namespace TeleBot.UI
|
||||
buttons.Add(new[] {
|
||||
InlineKeyboardButton.WithCallbackData(
|
||||
$"❌ Remove {item.ProductName}",
|
||||
$"remove:{item.ProductId}"
|
||||
_mapper.BuildCallback("remove", item.ProductId)
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user