update
This commit is contained in:
parent
027a3fd0c4
commit
5c6abe5686
@ -128,6 +128,14 @@ namespace TeleBot.Handlers
|
||||
await HandleSupportCallback(bot, callbackQuery, session);
|
||||
break;
|
||||
|
||||
case "refresh_conversation":
|
||||
await HandleRefreshConversation(bot, callbackQuery, session);
|
||||
break;
|
||||
|
||||
case "exit_chat":
|
||||
await HandleExitChat(bot, callbackQuery, session);
|
||||
break;
|
||||
|
||||
case "noop":
|
||||
// No operation - used for display-only buttons
|
||||
break;
|
||||
@ -605,19 +613,88 @@ namespace TeleBot.Handlers
|
||||
{
|
||||
session.State = SessionState.CustomerSupport;
|
||||
|
||||
await ShowCustomerConversationInCallback(bot, callbackQuery, session);
|
||||
await bot.AnswerCallbackQueryAsync(callbackQuery.Id);
|
||||
}
|
||||
|
||||
private async Task HandleRefreshConversation(ITelegramBotClient bot, CallbackQuery callbackQuery, UserSession session)
|
||||
{
|
||||
await ShowCustomerConversationInCallback(bot, callbackQuery, session);
|
||||
await bot.AnswerCallbackQueryAsync(callbackQuery.Id, "Messages refreshed");
|
||||
}
|
||||
|
||||
private async Task HandleExitChat(ITelegramBotClient bot, CallbackQuery callbackQuery, UserSession session)
|
||||
{
|
||||
session.State = SessionState.MainMenu;
|
||||
|
||||
await bot.EditMessageTextAsync(
|
||||
callbackQuery.Message!.Chat.Id,
|
||||
callbackQuery.Message.MessageId,
|
||||
"🎧 *Customer Support*\n\n" +
|
||||
"You can now send a message to our support team. Simply type your message and we'll respond as soon as possible.\n\n" +
|
||||
"_Type your message below, or use the Cancel button to return to the main menu._",
|
||||
parseMode: Telegram.Bot.Types.Enums.ParseMode.Markdown,
|
||||
replyMarkup: MenuBuilder.SupportMenu()
|
||||
"Chat ended. How can I help you today?",
|
||||
replyMarkup: MenuBuilder.MainMenu()
|
||||
);
|
||||
|
||||
await bot.AnswerCallbackQueryAsync(callbackQuery.Id);
|
||||
}
|
||||
|
||||
private async Task ShowCustomerConversationInCallback(ITelegramBotClient bot, CallbackQuery callbackQuery, UserSession session)
|
||||
{
|
||||
try
|
||||
{
|
||||
var user = callbackQuery.From;
|
||||
|
||||
// Get conversation history for this customer
|
||||
var messages = await _shopService.GetCustomerConversationAsync(
|
||||
user.Id,
|
||||
user.Username ?? "",
|
||||
$"{user.FirstName} {user.LastName}".Trim(),
|
||||
user.FirstName ?? "",
|
||||
user.LastName ?? ""
|
||||
);
|
||||
|
||||
var conversationText = "💬 *Your Messages*\n\n";
|
||||
|
||||
if (messages?.Any() == true)
|
||||
{
|
||||
conversationText += "Recent conversation:\n\n";
|
||||
|
||||
foreach (var msg in messages.OrderBy(m => m.CreatedAt).TakeLast(8)) // Show last 8 messages
|
||||
{
|
||||
var isFromBusiness = msg.Direction == 0; // AdminToCustomer
|
||||
var sender = isFromBusiness ? "🏪 Shop" : "👤 You";
|
||||
var time = msg.CreatedAt.ToString("MMM dd, HH:mm");
|
||||
|
||||
conversationText += $"*{sender}* _{time}_\n{msg.Content}\n\n";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
conversationText += "No messages yet. Start a conversation by typing below!\n\n";
|
||||
}
|
||||
|
||||
conversationText += "_Type your message or use buttons below._";
|
||||
|
||||
await bot.EditMessageTextAsync(
|
||||
callbackQuery.Message!.Chat.Id,
|
||||
callbackQuery.Message.MessageId,
|
||||
conversationText,
|
||||
parseMode: Telegram.Bot.Types.Enums.ParseMode.Markdown,
|
||||
replyMarkup: MenuBuilder.ConversationMenu()
|
||||
);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error showing customer conversation in callback");
|
||||
await bot.EditMessageTextAsync(
|
||||
callbackQuery.Message!.Chat.Id,
|
||||
callbackQuery.Message.MessageId,
|
||||
"💬 *Customer Messages*\n\nReady to chat with our support team!\n\n_Type your message below._",
|
||||
parseMode: Telegram.Bot.Types.Enums.ParseMode.Markdown,
|
||||
replyMarkup: MenuBuilder.ConversationMenu()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task HandleCancelSupport(ITelegramBotClient bot, CallbackQuery callbackQuery, UserSession session)
|
||||
{
|
||||
session.State = SessionState.MainMenu;
|
||||
|
||||
@ -158,19 +158,14 @@ namespace TeleBot.Handlers
|
||||
|
||||
private async Task HandleOrdersCommand(ITelegramBotClient bot, Message message, Models.UserSession session)
|
||||
{
|
||||
// Get or create identity reference for this user
|
||||
var identityRef = session.OrderFlow?.IdentityReference;
|
||||
if (string.IsNullOrEmpty(identityRef))
|
||||
{
|
||||
identityRef = _privacyService.GenerateAnonymousReference();
|
||||
if (session.OrderFlow == null)
|
||||
{
|
||||
session.OrderFlow = new Models.OrderFlowData();
|
||||
}
|
||||
session.OrderFlow.IdentityReference = identityRef;
|
||||
}
|
||||
|
||||
var orders = await _shopService.GetOrdersAsync(identityRef);
|
||||
// Use new customer-based order lookup
|
||||
var orders = await _shopService.GetCustomerOrdersAsync(
|
||||
message.From!.Id,
|
||||
message.From.Username ?? "",
|
||||
$"{message.From.FirstName} {message.From.LastName}".Trim(),
|
||||
message.From.FirstName ?? "",
|
||||
message.From.LastName ?? ""
|
||||
);
|
||||
|
||||
if (!orders.Any())
|
||||
{
|
||||
@ -310,14 +305,8 @@ namespace TeleBot.Handlers
|
||||
{
|
||||
session.State = Models.SessionState.CustomerSupport;
|
||||
|
||||
await bot.SendTextMessageAsync(
|
||||
message.Chat.Id,
|
||||
"🎧 *Customer Support*\n\n" +
|
||||
"You can now send a message to our support team. Simply type your message and we'll respond as soon as possible.\n\n" +
|
||||
"_Type your message below, or use /cancel to return to the main menu._",
|
||||
parseMode: Telegram.Bot.Types.Enums.ParseMode.Markdown,
|
||||
replyMarkup: MenuBuilder.SupportMenu()
|
||||
);
|
||||
// Show conversation history first
|
||||
await ShowCustomerConversation(bot, message, session);
|
||||
}
|
||||
|
||||
private async Task HandleCancelCommand(ITelegramBotClient bot, Message message, Models.UserSession session)
|
||||
@ -330,5 +319,59 @@ namespace TeleBot.Handlers
|
||||
replyMarkup: MenuBuilder.MainMenu()
|
||||
);
|
||||
}
|
||||
|
||||
private async Task ShowCustomerConversation(ITelegramBotClient bot, Message message, Models.UserSession session)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Get conversation history for this customer
|
||||
var messages = await _shopService.GetCustomerConversationAsync(
|
||||
message.From!.Id,
|
||||
message.From.Username ?? "",
|
||||
$"{message.From.FirstName} {message.From.LastName}".Trim(),
|
||||
message.From.FirstName ?? "",
|
||||
message.From.LastName ?? ""
|
||||
);
|
||||
|
||||
var conversationText = "💬 *Your Messages*\n\n";
|
||||
|
||||
if (messages?.Any() == true)
|
||||
{
|
||||
conversationText += "Here's your conversation history:\n\n";
|
||||
|
||||
foreach (var msg in messages.OrderBy(m => m.CreatedAt).Take(10)) // Show last 10 messages
|
||||
{
|
||||
var isFromBusiness = msg.Direction == 0; // AdminToCustomer
|
||||
var sender = isFromBusiness ? "🏪 Shop" : "👤 You";
|
||||
var time = msg.CreatedAt.ToString("MMM dd, HH:mm");
|
||||
|
||||
conversationText += $"*{sender}* _{time}_\n{msg.Content}\n\n";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
conversationText += "No messages yet. Start a conversation by typing below!\n\n";
|
||||
}
|
||||
|
||||
conversationText += "_Type your message or use the Exit Chat button to return to shopping._";
|
||||
|
||||
await bot.SendTextMessageAsync(
|
||||
message.Chat.Id,
|
||||
conversationText,
|
||||
parseMode: Telegram.Bot.Types.Enums.ParseMode.Markdown,
|
||||
replyMarkup: MenuBuilder.ConversationMenu()
|
||||
);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error showing customer conversation");
|
||||
await bot.SendTextMessageAsync(
|
||||
message.Chat.Id,
|
||||
"🎧 *Customer Support*\n\nReady to chat with our support team!\n\n_Type your message below._",
|
||||
parseMode: Telegram.Bot.Types.Enums.ParseMode.Markdown,
|
||||
replyMarkup: MenuBuilder.ConversationMenu()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -247,16 +247,8 @@ namespace TeleBot.Handlers
|
||||
|
||||
if (success)
|
||||
{
|
||||
await bot.SendTextMessageAsync(
|
||||
message.Chat.Id,
|
||||
"✅ *Message sent to support team*\n\n" +
|
||||
"We've received your message and will respond as soon as possible.\n\n" +
|
||||
"You can continue shopping or send additional messages.",
|
||||
parseMode: Telegram.Bot.Types.Enums.ParseMode.Markdown,
|
||||
replyMarkup: MenuBuilder.MainMenu()
|
||||
);
|
||||
|
||||
session.State = SessionState.MainMenu;
|
||||
// Show updated conversation instead of going back to main menu
|
||||
await RefreshCustomerConversation(bot, message, session);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -277,5 +269,54 @@ namespace TeleBot.Handlers
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task RefreshCustomerConversation(ITelegramBotClient bot, Message message, UserSession session)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Get updated conversation history
|
||||
var messages = await _shopService.GetCustomerConversationAsync(
|
||||
message.From!.Id,
|
||||
message.From.Username ?? "",
|
||||
$"{message.From.FirstName} {message.From.LastName}".Trim(),
|
||||
message.From.FirstName ?? "",
|
||||
message.From.LastName ?? ""
|
||||
);
|
||||
|
||||
var conversationText = "💬 *Your Messages*\n\n";
|
||||
|
||||
if (messages?.Any() == true)
|
||||
{
|
||||
conversationText += "Recent conversation:\n\n";
|
||||
|
||||
foreach (var msg in messages.OrderBy(m => m.CreatedAt).TakeLast(8)) // Show last 8 messages
|
||||
{
|
||||
var isFromBusiness = msg.Direction == 0; // AdminToCustomer
|
||||
var sender = isFromBusiness ? "🏪 Shop" : "👤 You";
|
||||
var time = msg.CreatedAt.ToString("MMM dd, HH:mm");
|
||||
|
||||
conversationText += $"*{sender}* _{time}_\n{msg.Content}\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
conversationText += "_Type your next message or use buttons below._";
|
||||
|
||||
await bot.SendTextMessageAsync(
|
||||
message.Chat.Id,
|
||||
conversationText,
|
||||
parseMode: Telegram.Bot.Types.Enums.ParseMode.Markdown,
|
||||
replyMarkup: MenuBuilder.ConversationMenu()
|
||||
);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error refreshing customer conversation");
|
||||
await bot.SendTextMessageAsync(
|
||||
message.Chat.Id,
|
||||
"✅ Message sent! Continue chatting or use the buttons below.",
|
||||
replyMarkup: MenuBuilder.ConversationMenu()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -18,12 +18,14 @@ namespace TeleBot.Services
|
||||
Task<Product?> GetProductAsync(Guid productId);
|
||||
Task<Order?> CreateOrderAsync(UserSession session, long telegramUserId = 0, string telegramUsername = "", string telegramDisplayName = "", string telegramFirstName = "", string telegramLastName = "");
|
||||
Task<List<Order>> GetOrdersAsync(string identityReference);
|
||||
Task<List<Order>> GetCustomerOrdersAsync(long telegramUserId, string telegramUsername, string displayName, string firstName, string lastName);
|
||||
Task<Order?> GetOrderAsync(Guid orderId);
|
||||
Task<CryptoPayment?> CreatePaymentAsync(Guid orderId, string currency);
|
||||
Task<List<CustomerMessage>?> GetPendingMessagesAsync();
|
||||
Task<bool> MarkMessageAsSentAsync(Guid messageId, string? platformMessageId = null);
|
||||
Task<bool> MarkMessageAsFailedAsync(Guid messageId, string reason);
|
||||
Task<bool> SendCustomerMessageAsync(long telegramUserId, string telegramUsername, string displayName, string firstName, string lastName, string subject, string content);
|
||||
Task<List<CustomerMessage>?> GetCustomerConversationAsync(long telegramUserId, string telegramUsername, string displayName, string firstName, string lastName);
|
||||
}
|
||||
|
||||
public class LittleShopService : ILittleShopService
|
||||
@ -450,5 +452,95 @@ namespace TeleBot.Services
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<List<Order>> GetCustomerOrdersAsync(long telegramUserId, string telegramUsername, string displayName, string firstName, string lastName)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!await AuthenticateAsync())
|
||||
return new List<Order>();
|
||||
|
||||
// Get or create the customer
|
||||
var customer = await _client.Customers.GetOrCreateCustomerAsync(new CreateCustomerRequest
|
||||
{
|
||||
TelegramUserId = telegramUserId,
|
||||
TelegramUsername = telegramUsername,
|
||||
TelegramDisplayName = displayName,
|
||||
TelegramFirstName = firstName,
|
||||
TelegramLastName = lastName,
|
||||
AllowOrderUpdates = true,
|
||||
AllowMarketing = false
|
||||
});
|
||||
|
||||
if (!customer.IsSuccess || customer.Data == null)
|
||||
{
|
||||
return new List<Order>();
|
||||
}
|
||||
|
||||
// Get customer orders using the new endpoint
|
||||
var ordersResult = await _client.Orders.GetOrdersByCustomerIdAsync(customer.Data.Id);
|
||||
|
||||
if (ordersResult.IsSuccess && ordersResult.Data != null)
|
||||
{
|
||||
return ordersResult.Data;
|
||||
}
|
||||
|
||||
return new List<Order>();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error fetching customer orders");
|
||||
return new List<Order>();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<List<CustomerMessage>?> GetCustomerConversationAsync(long telegramUserId, string telegramUsername, string displayName, string firstName, string lastName)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!await AuthenticateAsync())
|
||||
return null;
|
||||
|
||||
// First, get or create the customer
|
||||
var customer = await _client.Customers.GetOrCreateCustomerAsync(new CreateCustomerRequest
|
||||
{
|
||||
TelegramUserId = telegramUserId,
|
||||
TelegramUsername = telegramUsername,
|
||||
TelegramDisplayName = displayName,
|
||||
TelegramFirstName = firstName,
|
||||
TelegramLastName = lastName,
|
||||
AllowOrderUpdates = true,
|
||||
AllowMarketing = false
|
||||
});
|
||||
|
||||
if (!customer.IsSuccess || customer.Data == null)
|
||||
{
|
||||
return new List<CustomerMessage>();
|
||||
}
|
||||
|
||||
// Get all messages for this customer (conversation history)
|
||||
var clientMessages = await _client.Messages.GetCustomerMessagesAsync(customer.Data.Id);
|
||||
|
||||
// Convert to TeleBot CustomerMessage format
|
||||
return clientMessages?.Select(m => new CustomerMessage
|
||||
{
|
||||
Id = m.Id,
|
||||
CustomerId = m.CustomerId,
|
||||
TelegramUserId = m.TelegramUserId,
|
||||
Subject = m.Subject,
|
||||
Content = m.Content,
|
||||
Type = (MessageType)m.Type,
|
||||
IsUrgent = m.IsUrgent,
|
||||
OrderReference = m.OrderReference,
|
||||
CreatedAt = m.CreatedAt,
|
||||
Direction = m.Direction
|
||||
}).ToList() ?? new List<CustomerMessage>();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error getting customer conversation");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -187,6 +187,7 @@ namespace TeleBot.Services
|
||||
public bool IsUrgent { get; set; }
|
||||
public string? OrderReference { get; set; }
|
||||
public DateTime CreatedAt { get; set; }
|
||||
public int Direction { get; set; } // 0 = AdminToCustomer, 1 = CustomerToAdmin
|
||||
}
|
||||
|
||||
public class PendingMessageDto
|
||||
|
||||
@ -154,8 +154,8 @@ namespace TeleBot.Services
|
||||
session.LastActivityAt = DateTime.UtcNow;
|
||||
_inMemorySessions.AddOrUpdate(session.Id, session, (key, old) => session);
|
||||
|
||||
// Don't persist ephemeral sessions
|
||||
if (session.IsEphemeral)
|
||||
// Don't persist ephemeral sessions, except when in checkout flow
|
||||
if (session.IsEphemeral && session.State != SessionState.CheckoutFlow)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@ -16,7 +16,7 @@ namespace TeleBot.UI
|
||||
new[] { InlineKeyboardButton.WithCallbackData("🛍️ Browse Products", "browse") },
|
||||
new[] { InlineKeyboardButton.WithCallbackData("🛒 View Cart", "cart") },
|
||||
new[] { InlineKeyboardButton.WithCallbackData("📦 My Orders", "orders") },
|
||||
new[] { InlineKeyboardButton.WithCallbackData("🎧 Customer Support", "support") },
|
||||
new[] { InlineKeyboardButton.WithCallbackData("💬 Messages", "support") },
|
||||
new[] { InlineKeyboardButton.WithCallbackData("🔒 Privacy Settings", "privacy") },
|
||||
new[] { InlineKeyboardButton.WithCallbackData("❓ Help", "help") }
|
||||
});
|
||||
@ -291,6 +291,20 @@ namespace TeleBot.UI
|
||||
return markup;
|
||||
}
|
||||
|
||||
public static InlineKeyboardMarkup ConversationMenu()
|
||||
{
|
||||
var markup = new InlineKeyboardMarkup(new[]
|
||||
{
|
||||
new[]
|
||||
{
|
||||
InlineKeyboardButton.WithCallbackData("🔄 Refresh Messages", "refresh_conversation"),
|
||||
InlineKeyboardButton.WithCallbackData("⬅️ Back to Menu", "exit_chat")
|
||||
}
|
||||
});
|
||||
|
||||
return markup;
|
||||
}
|
||||
|
||||
private static string GetOrderStatusEmoji(int status)
|
||||
{
|
||||
return status switch
|
||||
|
||||
@ -256,7 +256,7 @@ namespace TeleBot.UI
|
||||
"/browse - Browse products\n" +
|
||||
"/cart - View shopping cart\n" +
|
||||
"/orders - View your orders\n" +
|
||||
"/support - Contact customer support\n" +
|
||||
"/support - View messages and chat\n" +
|
||||
"/privacy - Privacy settings\n" +
|
||||
"/pgpkey - Set PGP public key\n" +
|
||||
"/ephemeral - Toggle ephemeral mode\n" +
|
||||
|
||||
Loading…
Reference in New Issue
Block a user