diff --git a/TeleBot/TeleBot/Handlers/CallbackHandler.cs b/TeleBot/TeleBot/Handlers/CallbackHandler.cs index 3d1b484..628d591 100644 --- a/TeleBot/TeleBot/Handlers/CallbackHandler.cs +++ b/TeleBot/TeleBot/Handlers/CallbackHandler.cs @@ -139,7 +139,23 @@ namespace TeleBot.Handlers case "checkout": await HandleCheckout(bot, callbackQuery.Message, session); break; - + + case "use_saved_address": + await HandleUseSavedAddress(bot, callbackQuery.Message, session); + break; + + case "enter_new_address": + await HandleEnterNewAddress(bot, callbackQuery.Message, session); + break; + + case "save_address_yes": + await HandleSaveAddressPreference(bot, callbackQuery.Message, session, true); + break; + + case "save_address_no": + await HandleSaveAddressPreference(bot, callbackQuery.Message, session, false); + break; + case "confirm_order": await HandleConfirmOrder(bot, callbackQuery.Message, session, callbackQuery.From); break; @@ -746,9 +762,81 @@ namespace TeleBot.Handlers session.State = SessionState.CheckoutFlow; - // Send new message for checkout - collect all details at once - await bot.SendTextMessageAsync( + // Check if user has saved address + if (session.SavedAddress != null && !string.IsNullOrWhiteSpace(session.SavedAddress.Name)) + { + // Offer to use saved address + var savedAddressPreview = $"{session.SavedAddress.Name}\n" + + $"{session.SavedAddress.Address}\n" + + $"{session.SavedAddress.City}\n" + + $"{session.SavedAddress.PostCode}\n" + + $"{session.SavedAddress.Country}"; + + await bot.SendTextMessageAsync( + message.Chat.Id, + $"📦 *Checkout - Delivery Details*\n\n" + + $"Use your saved address?\n\n" + + $"```\n{savedAddressPreview}\n```", + parseMode: Telegram.Bot.Types.Enums.ParseMode.Markdown, + replyMarkup: _menuBuilder.UseSavedAddressMenu() + ); + } + else + { + // Send new message for checkout - collect all details at once + await bot.SendTextMessageAsync( + message.Chat.Id, + "📦 *Checkout - Delivery Details*\n\n" + + "Please provide all delivery details in one message:\n\n" + + "• Full Name\n" + + "• Street Address\n" + + "• City\n" + + "• Post/Zip Code\n" + + "• Country (or leave blank for UK)\n\n" + + "_Example:_\n" + + "`John Smith\n" + + "123 Main Street\n" + + "London\n" + + "SW1A 1AA\n" + + "United Kingdom`", + parseMode: Telegram.Bot.Types.Enums.ParseMode.Markdown + ); + } + } + + private async Task HandleUseSavedAddress(ITelegramBotClient bot, Message message, UserSession session) + { + if (session.SavedAddress == null || session.OrderFlow == null) + { + await HandleEnterNewAddress(bot, message, session); + return; + } + + // Copy saved address to order flow + session.OrderFlow.ShippingName = session.SavedAddress.Name; + session.OrderFlow.ShippingAddress = session.SavedAddress.Address; + session.OrderFlow.ShippingCity = session.SavedAddress.City; + session.OrderFlow.ShippingPostCode = session.SavedAddress.PostCode; + session.OrderFlow.ShippingCountry = session.SavedAddress.Country; + session.OrderFlow.CurrentStep = OrderFlowStep.ReviewingOrder; + + // Show order summary + var summary = MessageFormatter.FormatOrderSummary(session.OrderFlow, session.Cart); + + await bot.EditMessageTextAsync( message.Chat.Id, + message.MessageId, + summary, + parseMode: Telegram.Bot.Types.Enums.ParseMode.Markdown, + replyMarkup: MenuBuilder.CheckoutConfirmMenu() + ); + } + + private async Task HandleEnterNewAddress(ITelegramBotClient bot, Message message, UserSession session) + { + await bot.EditMessageTextAsync( + message.Chat.Id, + message.MessageId, "📦 *Checkout - Delivery Details*\n\n" + "Please provide all delivery details in one message:\n\n" + "• Full Name\n" + @@ -765,7 +853,42 @@ namespace TeleBot.Handlers parseMode: Telegram.Bot.Types.Enums.ParseMode.Markdown ); } - + + private async Task HandleSaveAddressPreference(ITelegramBotClient bot, Message message, UserSession session, bool saveAddress) + { + // Save user preference + session.Privacy.SaveShippingAddress = saveAddress; + + if (saveAddress && session.OrderFlow != null) + { + // Save the address + session.SavedAddress = new SavedShippingAddress + { + Name = session.OrderFlow.ShippingName, + Address = session.OrderFlow.ShippingAddress, + City = session.OrderFlow.ShippingCity, + PostCode = session.OrderFlow.ShippingPostCode, + Country = session.OrderFlow.ShippingCountry, + SavedAt = DateTime.UtcNow + }; + } + + // Continue to order summary + if (session.OrderFlow != null) + { + session.OrderFlow.CurrentStep = OrderFlowStep.ReviewingOrder; + var summary = MessageFormatter.FormatOrderSummary(session.OrderFlow, session.Cart); + + await bot.EditMessageTextAsync( + message.Chat.Id, + message.MessageId, + summary, + parseMode: Telegram.Bot.Types.Enums.ParseMode.Markdown, + replyMarkup: MenuBuilder.CheckoutConfirmMenu() + ); + } + } + private async Task HandleConfirmOrder(ITelegramBotClient bot, Message message, UserSession session, User telegramUser) { if (session.OrderFlow == null || session.Cart.IsEmpty()) diff --git a/TeleBot/TeleBot/Handlers/MessageHandler.cs b/TeleBot/TeleBot/Handlers/MessageHandler.cs index 568af87..794ba93 100644 --- a/TeleBot/TeleBot/Handlers/MessageHandler.cs +++ b/TeleBot/TeleBot/Handlers/MessageHandler.cs @@ -132,18 +132,48 @@ namespace TeleBot.Handlers ? lines[4] : "United Kingdom"; - // Skip to review step - session.OrderFlow.CurrentStep = OrderFlowStep.ReviewingOrder; + // Check if we need to ask about saving address + if (session.Privacy.SaveShippingAddress == null) + { + // Haven't asked yet - offer to save + await bot.SendTextMessageAsync( + message.Chat.Id, + "💾 *Save Address*\n\n" + + "Would you like to save this address for future orders?\n\n" + + "_You will only be asked this once._", + parseMode: Telegram.Bot.Types.Enums.ParseMode.Markdown, + replyMarkup: new MenuBuilder(null!).SaveAddressConfirmMenu() + ); + } + else + { + // Already has preference - apply it automatically + if (session.Privacy.SaveShippingAddress == true) + { + session.SavedAddress = new SavedShippingAddress + { + Name = session.OrderFlow.ShippingName, + Address = session.OrderFlow.ShippingAddress, + City = session.OrderFlow.ShippingCity, + PostCode = session.OrderFlow.ShippingPostCode, + Country = session.OrderFlow.ShippingCountry, + SavedAt = DateTime.UtcNow + }; + } - // Show order summary - var summary = MessageFormatter.FormatOrderSummary(session.OrderFlow, session.Cart); + // Skip to review step + session.OrderFlow.CurrentStep = OrderFlowStep.ReviewingOrder; - await bot.SendTextMessageAsync( - message.Chat.Id, - summary, - parseMode: Telegram.Bot.Types.Enums.ParseMode.Markdown, - replyMarkup: MenuBuilder.CheckoutConfirmMenu() - ); + // Show order summary + var summary = MessageFormatter.FormatOrderSummary(session.OrderFlow, session.Cart); + + await bot.SendTextMessageAsync( + message.Chat.Id, + summary, + parseMode: Telegram.Bot.Types.Enums.ParseMode.Markdown, + replyMarkup: MenuBuilder.CheckoutConfirmMenu() + ); + } break; // Legacy steps - redirect to new single-message collection diff --git a/TeleBot/TeleBot/Models/UserSession.cs b/TeleBot/TeleBot/Models/UserSession.cs index d10cdde..fe5efa8 100644 --- a/TeleBot/TeleBot/Models/UserSession.cs +++ b/TeleBot/TeleBot/Models/UserSession.cs @@ -24,7 +24,10 @@ namespace TeleBot.Models public DateTime ExpiresAt { get; set; } public bool IsEphemeral { get; set; } = true; public PrivacySettings Privacy { get; set; } = new(); - + + // Saved shipping address (optional, based on user preference) + public SavedShippingAddress? SavedAddress { get; set; } + // Order flow data (temporary) public OrderFlowData? OrderFlow { get; set; } @@ -62,6 +65,19 @@ namespace TeleBot.Models public bool EnableDisappearingMessages { get; set; } = true; public int DisappearingMessageTTL { get; set; } = 30; // seconds + + // Address memory preference + public bool? SaveShippingAddress { get; set; } = null; // null = not asked yet, true = save, false = don't save + } + + public class SavedShippingAddress + { + public string? Name { get; set; } + public string? Address { get; set; } + public string? City { get; set; } + public string? PostCode { get; set; } + public string? Country { get; set; } + public DateTime? SavedAt { get; set; } } public class OrderFlowData diff --git a/TeleBot/TeleBot/UI/MenuBuilder.cs b/TeleBot/TeleBot/UI/MenuBuilder.cs index c9af725..e1588ef 100644 --- a/TeleBot/TeleBot/UI/MenuBuilder.cs +++ b/TeleBot/TeleBot/UI/MenuBuilder.cs @@ -210,13 +210,42 @@ namespace TeleBot.UI { return new InlineKeyboardMarkup(new[] { - new[] { + new[] { InlineKeyboardButton.WithCallbackData("✅ Confirm Order", "confirm_order"), InlineKeyboardButton.WithCallbackData("❌ Cancel", "cart") } }); } - + + public InlineKeyboardMarkup UseSavedAddressMenu() + { + return new InlineKeyboardMarkup(new[] + { + new[] { + InlineKeyboardButton.WithCallbackData("✅ Use Saved Address", "use_saved_address") + }, + new[] { + InlineKeyboardButton.WithCallbackData("✏️ Enter New Address", "enter_new_address") + }, + new[] { + InlineKeyboardButton.WithCallbackData("❌ Cancel", "cart") + } + }); + } + + public InlineKeyboardMarkup SaveAddressConfirmMenu() + { + return new InlineKeyboardMarkup(new[] + { + new[] { + InlineKeyboardButton.WithCallbackData("✅ Yes, Save My Address", "save_address_yes") + }, + new[] { + InlineKeyboardButton.WithCallbackData("❌ No, Don't Save", "save_address_no") + } + }); + } + public static InlineKeyboardMarkup PaymentMethodMenu(List currencies) { var buttons = new List();