From 99bb083bd68963e6a2f5d5b6da0eb3633155dd1c Mon Sep 17 00:00:00 2001 From: SysAdmin Date: Mon, 6 Oct 2025 03:29:11 +0100 Subject: [PATCH] Feature: Enhanced order display and basket summary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Basket Summary Below Navigation - Welcome message now shows basket items and total - Format: "šŸ›’ Basket: X item(s) - Ā£X.XX" - Only shown when basket has items 2. Order Display Improvements - Order GUID replaced with friendly reference (last 8 chars: #XXXXXXXX) - Added "View Payment Details" button for pending payment orders - Button shows QR code, amount, address, and time until expiry - Variants now properly displayed in order items (already working via commit 330116e) 3. Payment Details View (New Feature) - HandleViewPayment: Shows payment info with QR code - Displays: Currency, amount, address, expiry time - Shows time remaining until payment expires - QR code generation for easy mobile payment - OrderDetailsMenu: Context-aware navigation buttons 4. Postal Address Auto-Load (Verified Working) - Checkout automatically detects saved addresses - Offers to use saved address with preview - One-click selection or option to enter new address - SavedAddress copied to OrderFlow when selected Technical Changes: - MessageFormatter.FormatWelcome: Added optional cart parameter - MessageFormatter.FormatOrder: Uses friendly order reference - MenuBuilder.OrderDetailsMenu: New menu with payment button - CallbackHandler.HandleViewPayment: Payment details with QR - CallbackHandler.HandleMainMenu: Pass cart to welcome formatter šŸ¤– Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- TeleBot/TeleBot/Handlers/CallbackHandler.cs | 89 ++++++++++++++++++++- TeleBot/TeleBot/UI/MenuBuilder.cs | 22 +++++ TeleBot/TeleBot/UI/MessageFormatter.cs | 41 +++++++--- 3 files changed, 136 insertions(+), 16 deletions(-) diff --git a/TeleBot/TeleBot/Handlers/CallbackHandler.cs b/TeleBot/TeleBot/Handlers/CallbackHandler.cs index 94a9e7b..35db0c2 100644 --- a/TeleBot/TeleBot/Handlers/CallbackHandler.cs +++ b/TeleBot/TeleBot/Handlers/CallbackHandler.cs @@ -172,6 +172,10 @@ namespace TeleBot.Handlers await HandleViewOrder(bot, callbackQuery.Message, session, Guid.Parse(data[1]), callbackQuery.From); break; + case "payment": + await HandleViewPayment(bot, callbackQuery.Message, session, Guid.Parse(data[1]), callbackQuery.From); + break; + case "reviews": await HandleViewReviews(bot, callbackQuery.Message, session); break; @@ -256,7 +260,7 @@ namespace TeleBot.Handlers // Send new message at bottom instead of editing old one await bot.SendTextMessageAsync( message.Chat.Id, - MessageFormatter.FormatWelcome(true), + MessageFormatter.FormatWelcome(true, session.Cart), parseMode: Telegram.Bot.Types.Enums.ParseMode.Markdown, replyMarkup: MenuBuilder.MainMenu() ); @@ -1166,12 +1170,91 @@ namespace TeleBot.Handlers message.Chat.Id, MessageFormatter.FormatOrder(order), parseMode: Telegram.Bot.Types.Enums.ParseMode.Markdown, - replyMarkup: MenuBuilder.MainMenu() + replyMarkup: _menuBuilder.OrderDetailsMenu(order) ); session.State = SessionState.ViewingOrder; } - + + private async Task HandleViewPayment(ITelegramBotClient bot, Message message, UserSession session, Guid orderId, User telegramUser) + { + var order = await _shopService.GetCustomerOrderAsync( + orderId, + telegramUser.Id, + telegramUser.Username ?? "", + $"{telegramUser.FirstName} {telegramUser.LastName}".Trim(), + telegramUser.FirstName ?? "", + telegramUser.LastName ?? "" + ); + + if (order == null) + { + await bot.AnswerCallbackQueryAsync("", "Order not found", showAlert: true); + return; + } + + var payment = order.Payments.FirstOrDefault(p => p.Status == 0); // Find pending payment + if (payment == null) + { + await bot.SendTextMessageAsync( + message.Chat.Id, + "No pending payment found for this order.", + replyMarkup: _menuBuilder.OrderDetailsMenu(order) + ); + return; + } + + var paymentText = MessageFormatter.FormatPayment(payment); + + // Calculate time until expiry + var timeUntilExpiry = payment.ExpiresAt - DateTime.UtcNow; + if (timeUntilExpiry.TotalMinutes > 0) + { + paymentText += $"\nā° *Time remaining:* {timeUntilExpiry.Hours}h {timeUntilExpiry.Minutes}m"; + } + + // Generate QR code if enabled + if (_configuration.GetValue("Features:EnableQRCodes")) + { + try + { + using var qrGenerator = new QRCodeGenerator(); + var qrCodeData = qrGenerator.CreateQrCode(payment.WalletAddress, QRCodeGenerator.ECCLevel.Q); + using var qrCode = new PngByteQRCode(qrCodeData); + var qrCodeBytes = qrCode.GetGraphic(10); + + using var stream = new System.IO.MemoryStream(qrCodeBytes); + await bot.SendPhotoAsync( + message.Chat.Id, + InputFile.FromStream(stream, "payment_qr.png"), + caption: paymentText, + parseMode: Telegram.Bot.Types.Enums.ParseMode.Markdown, + replyMarkup: _menuBuilder.OrderDetailsMenu(order) + ); + } + catch (Exception ex) + { + _logger.LogError(ex, "Failed to generate QR code for payment view"); + // Fall back to text-only + await bot.SendTextMessageAsync( + message.Chat.Id, + paymentText, + parseMode: Telegram.Bot.Types.Enums.ParseMode.Markdown, + replyMarkup: _menuBuilder.OrderDetailsMenu(order) + ); + } + } + else + { + await bot.SendTextMessageAsync( + message.Chat.Id, + paymentText, + parseMode: Telegram.Bot.Types.Enums.ParseMode.Markdown, + replyMarkup: _menuBuilder.OrderDetailsMenu(order) + ); + } + } + private async Task HandlePrivacySettings(ITelegramBotClient bot, Message message, UserSession session, string? setting) { if (setting != null) diff --git a/TeleBot/TeleBot/UI/MenuBuilder.cs b/TeleBot/TeleBot/UI/MenuBuilder.cs index 6b2a768..075678d 100644 --- a/TeleBot/TeleBot/UI/MenuBuilder.cs +++ b/TeleBot/TeleBot/UI/MenuBuilder.cs @@ -206,6 +206,28 @@ namespace TeleBot.UI return new InlineKeyboardMarkup(buttons); } + public InlineKeyboardMarkup OrderDetailsMenu(Order order) + { + var buttons = new List(); + + // If order has pending payment, show payment details button + if (order.Status == 0 && order.Payments.Any(p => p.Status == 0)) // PendingPayment order with pending payment + { + buttons.Add(new[] + { + InlineKeyboardButton.WithCallbackData("šŸ’³ View Payment Details", $"payment:{order.Id}") + }); + } + + buttons.Add(new[] + { + InlineKeyboardButton.WithCallbackData("ā¬…ļø Back to Orders", "orders"), + InlineKeyboardButton.WithCallbackData("šŸ  Main Menu", "menu") + }); + + return new InlineKeyboardMarkup(buttons); + } + public InlineKeyboardMarkup CartMenu(ShoppingCart cart) { var buttons = new List(); diff --git a/TeleBot/TeleBot/UI/MessageFormatter.cs b/TeleBot/TeleBot/UI/MessageFormatter.cs index ed03896..2d0acbf 100644 --- a/TeleBot/TeleBot/UI/MessageFormatter.cs +++ b/TeleBot/TeleBot/UI/MessageFormatter.cs @@ -8,24 +8,36 @@ namespace TeleBot.UI { public static class MessageFormatter { - public static string FormatWelcome(bool isReturning) + public static string FormatWelcome(bool isReturning, ShoppingCart? cart = null) { + var message = ""; + if (isReturning) { - return $"šŸ”’ *Welcome back to {BotConfig.BrandName}*\n\n" + + message = $"šŸ”’ *Welcome back to {BotConfig.BrandName}*\n\n" + "Your privacy is our priority. All sessions are ephemeral by default.\n\n" + "šŸ–¼ļø *New Feature:* Browse products with beautiful image carousels!\n\n" + "How can I help you today?"; } - - return $"šŸ”’ *Welcome to {BotConfig.BrandName}*\n\n" + - "šŸ›”ļø *Your Privacy Matters:*\n" + - "• No account required\n" + - "• Ephemeral sessions by default\n" + - "• Optional PGP encryption for shipping\n" + - "• Cryptocurrency payments only\n\n" + - "šŸ–¼ļø *New Feature:* Browse products with beautiful image carousels!\n\n" + - "Use /help for available commands or choose from the menu below:"; + else + { + message = $"šŸ”’ *Welcome to {BotConfig.BrandName}*\n\n" + + "šŸ›”ļø *Your Privacy Matters:*\n" + + "• No account required\n" + + "• Ephemeral sessions by default\n" + + "• Optional PGP encryption for shipping\n" + + "• Cryptocurrency payments only\n\n" + + "šŸ–¼ļø *New Feature:* Browse products with beautiful image carousels!\n\n" + + "Use /help for available commands or choose from the menu below:"; + } + + // Add basket summary if items present + if (cart != null && !cart.IsEmpty()) + { + message += $"\n\nšŸ›’ *Basket:* {cart.GetTotalItems()} item(s) - Ā£{cart.GetTotalAmount():F2}"; + } + + return message; } public static string FormatCategories(List categories) @@ -271,9 +283,12 @@ namespace TeleBot.UI public static string FormatOrder(Order order) { var sb = new StringBuilder(); - + + // Generate friendly order reference from GUID (last 8 characters) + var orderRef = order.Id.ToString().Substring(order.Id.ToString().Length - 8).ToUpper(); + sb.AppendLine($"šŸ“¦ *Order Details*\n"); - sb.AppendLine($"*Order ID:* `{order.Id}`"); + sb.AppendLine($"*Order Reference:* `#{orderRef}`"); sb.AppendLine($"*Status:* {FormatOrderStatus(order.Status)}"); sb.AppendLine($"*Total:* Ā£{order.TotalAmount:F2}"); sb.AppendLine($"*Created:* {order.CreatedAt:yyyy-MM-dd HH:mm} UTC");