littleshop/TeleBot/TeleBot/UI/MessageFormatter.cs
SysAdmin 5013e60358 Fix TeleBot compilation errors - use RequiredAmount property
- Fixed CryptoAmount property that doesn't exist
- Display £ amounts with note about needing conversion
- Show actual crypto amounts when less than 1.0
2025-09-24 19:26:40 +01:00

437 lines
17 KiB
C#
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Linq;
using System.Text;
using LittleShop.Client.Models;
using TeleBot.Models;
namespace TeleBot.UI
{
public static class MessageFormatter
{
public static string FormatWelcome(bool isReturning)
{
if (isReturning)
{
return $"🔒 *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:";
}
public static string FormatCategories(List<Category> categories)
{
var sb = new StringBuilder();
sb.AppendLine("**PRODUCT CATEGORIES**\n");
sb.AppendLine("Choose a category to start shopping:");
return sb.ToString();
}
public static string FormatProductList(PagedResult<Product> products, string? categoryName = null)
{
var sb = new StringBuilder();
if (!string.IsNullOrEmpty(categoryName))
{
sb.AppendLine($"📦 *Products in {categoryName}*\n");
}
else
{
sb.AppendLine("📦 *All Products*\n");
}
if (!products.Items.Any())
{
sb.AppendLine("No products available in this category.");
return sb.ToString();
}
foreach (var product in products.Items)
{
sb.AppendLine($"*{product.Name}*");
sb.AppendLine($"💰 Price: £{product.Price:F2}");
if (!string.IsNullOrEmpty(product.Description))
{
var desc = product.Description.Length > 100
? product.Description.Substring(0, 97) + "..."
: product.Description;
sb.AppendLine($"_{desc}_");
}
sb.AppendLine();
}
if (products.TotalPages > 1)
{
sb.AppendLine($"Page {products.PageNumber} of {products.TotalPages}");
}
return sb.ToString();
}
public static string FormatSingleProduct(Product product)
{
var sb = new StringBuilder();
sb.AppendLine($"🛍️ *{product.Name}*");
// Show multi-buys if available
if (product.MultiBuys?.Any() == true)
{
var lowestPrice = product.MultiBuys.Min(mb => mb.PricePerUnit);
sb.AppendLine($"💰 From £{lowestPrice:F2}");
sb.AppendLine($"📦 _{product.MultiBuys.Count} multi-buy options_");
}
else
{
sb.AppendLine($"💰 £{product.Price:F2}");
}
// Show variants if available
if (product.Variants?.Any() == true)
{
var variantTypes = product.Variants.Select(v => v.VariantType).Distinct().FirstOrDefault() ?? "options";
sb.AppendLine($"🎨 _{product.Variants.Count} {variantTypes.ToLower()} available_");
}
if (!string.IsNullOrEmpty(product.Description))
{
// Truncate description for bubble format
var desc = product.Description.Length > 100
? product.Description.Substring(0, 100) + "..."
: product.Description;
sb.AppendLine($"\n_{desc}_");
}
return sb.ToString();
}
public static string FormatProductDetail(Product product)
{
var sb = new StringBuilder();
sb.AppendLine($"🛍️ *{product.Name}*\n");
sb.AppendLine($"💰 *Price:* £{product.Price:F2}");
sb.AppendLine($"⚖️ *Weight:* {product.Weight} {product.WeightUnit}");
sb.AppendLine($"📁 *Category:* {product.CategoryName ?? "Uncategorized"}");
if (!string.IsNullOrEmpty(product.Description))
{
sb.AppendLine($"\n📝 *Description:*\n{product.Description}");
}
if (product.Photos.Any())
{
sb.AppendLine($"\n🖼 _{product.Photos.Count} photo(s) available_");
}
sb.AppendLine("\nSelect quantity and add to cart:");
return sb.ToString();
}
public static string FormatProductWithMultiBuys(Product product)
{
var sb = new StringBuilder();
sb.AppendLine($"🛍️ *{product.Name}*\n");
if (product.MultiBuys?.Any() == true)
{
sb.AppendLine("📦 *Multi-Buy Options:*\n");
foreach (var multiBuy in product.MultiBuys.OrderBy(mb => mb.Quantity))
{
var savings = multiBuy.Quantity > 1
? $" (£{multiBuy.PricePerUnit:F2} each)"
: "";
sb.AppendLine($"• *{multiBuy.Name}*: £{multiBuy.Price:F2}{savings}");
if (!string.IsNullOrEmpty(multiBuy.Description))
{
sb.AppendLine($" _{multiBuy.Description}_");
}
}
}
else
{
sb.AppendLine($"💰 *Price:* £{product.Price:F2}");
}
if (product.Variants?.Any() == true)
{
var variantTypes = product.Variants.Select(v => v.VariantType).Distinct().FirstOrDefault() ?? "Variant";
sb.AppendLine($"\n🎨 *{variantTypes} Options:*");
var variantNames = string.Join(", ", product.Variants.OrderBy(v => v.SortOrder).Select(v => v.Name));
sb.AppendLine($"_{variantNames}_");
}
sb.AppendLine($"\n⚖ *Weight:* {product.Weight} {product.WeightUnit}");
sb.AppendLine($"📁 *Category:* {product.CategoryName ?? "Uncategorized"}");
if (!string.IsNullOrEmpty(product.Description))
{
sb.AppendLine($"\n📝 *Description:*\n{product.Description}");
}
sb.AppendLine("\n*Select an option to add to cart:*");
return sb.ToString();
}
public static string FormatCart(ShoppingCart cart)
{
var sb = new StringBuilder();
sb.AppendLine("🛒 *Shopping Cart*\n");
if (cart.IsEmpty())
{
sb.AppendLine("Your cart is empty.\n");
sb.AppendLine("Browse products to add items to your cart.");
return sb.ToString();
}
foreach (var item in cart.Items)
{
sb.AppendLine($"• *{item.ProductName}*");
sb.AppendLine($" Qty: {item.Quantity} × £{item.UnitPrice:F2} = *£{item.TotalPrice:F2}*");
}
sb.AppendLine($"\n📊 *Summary:*");
sb.AppendLine($"Items: {cart.GetTotalItems()}");
sb.AppendLine($"*Total: £{cart.GetTotalAmount():F2}*");
return sb.ToString();
}
public static string FormatOrderSummary(OrderFlowData orderFlow, ShoppingCart cart)
{
var sb = new StringBuilder();
sb.AppendLine("📋 *Order Summary*\n");
sb.AppendLine("*Shipping Information:*");
if (orderFlow.UsePGPEncryption)
{
sb.AppendLine("🔐 _Shipping details will be PGP encrypted_");
}
else
{
sb.AppendLine($"Name: {orderFlow.ShippingName}");
sb.AppendLine($"Address: {orderFlow.ShippingAddress}");
sb.AppendLine($"City: {orderFlow.ShippingCity}");
sb.AppendLine($"Post Code: {orderFlow.ShippingPostCode}");
sb.AppendLine($"Country: {orderFlow.ShippingCountry}");
}
if (!string.IsNullOrEmpty(orderFlow.Notes))
{
sb.AppendLine($"Notes: {orderFlow.Notes}");
}
sb.AppendLine($"\n*Order Total: £{cart.GetTotalAmount():F2}*");
sb.AppendLine($"Items: {cart.GetTotalItems()}");
sb.AppendLine("\nPlease confirm your order:");
return sb.ToString();
}
public static string FormatOrder(Order order)
{
var sb = new StringBuilder();
sb.AppendLine($"📦 *Order Details*\n");
sb.AppendLine($"*Order ID:* `{order.Id}`");
sb.AppendLine($"*Status:* {FormatOrderStatus(order.Status)}");
sb.AppendLine($"*Total:* £{order.TotalAmount:F2}");
sb.AppendLine($"*Created:* {order.CreatedAt:yyyy-MM-dd HH:mm} UTC");
if (order.PaidAt.HasValue)
{
sb.AppendLine($"*Paid:* {order.PaidAt.Value:yyyy-MM-dd HH:mm} UTC");
}
if (order.ShippedAt.HasValue)
{
sb.AppendLine($"*Shipped:* {order.ShippedAt.Value:yyyy-MM-dd HH:mm} UTC");
}
if (!string.IsNullOrEmpty(order.TrackingNumber))
{
sb.AppendLine($"*Tracking:* `{order.TrackingNumber}`");
}
if (order.Items.Any())
{
sb.AppendLine("\n*Items:*");
foreach (var item in order.Items)
{
sb.AppendLine($"• {item.ProductName} - Qty: {item.Quantity} - £{item.TotalPrice:F2}");
}
}
if (order.Payments.Any())
{
sb.AppendLine("\n*Payments:*");
foreach (var payment in order.Payments)
{
sb.AppendLine($"• {FormatCurrency(payment.Currency)}: {FormatPaymentStatus(payment.Status)}");
if (!string.IsNullOrEmpty(payment.WalletAddress))
{
sb.AppendLine($" Address: `{payment.WalletAddress}`");
}
// Check if amount looks like a crypto amount (less than 1 for typical orders)
var isCryptoAmount = payment.RequiredAmount < 1.0m;
var amountDisplay = isCryptoAmount
? $"{payment.RequiredAmount:F8} {FormatCurrency(payment.Currency)}"
: $"£{payment.RequiredAmount:F2} (needs conversion to {FormatCurrency(payment.Currency)})";
sb.AppendLine($" Amount: {amountDisplay}");
}
}
return sb.ToString();
}
public static string FormatPayment(CryptoPayment payment)
{
var sb = new StringBuilder();
sb.AppendLine($"💰 *Payment Instructions*\n");
sb.AppendLine($"*Currency:* {FormatCurrency(payment.Currency)}");
// Check if amount looks like a crypto amount (less than 1 for typical orders)
var isCryptoAmount = payment.RequiredAmount < 1.0m;
if (isCryptoAmount)
{
sb.AppendLine($"*Amount:* `{payment.RequiredAmount:F8} {FormatCurrency(payment.Currency)}`");
}
else
{
// This looks like a GBP amount that needs conversion
sb.AppendLine($"*Order Total:* £{payment.RequiredAmount:F2}");
sb.AppendLine($"*Note:* Amount needs conversion to {FormatCurrency(payment.Currency)}");
sb.AppendLine($"*Please check payment link for actual crypto amount*");
}
sb.AppendLine($"*Status:* {FormatPaymentStatus(payment.Status)}");
sb.AppendLine($"*Expires:* {payment.ExpiresAt:yyyy-MM-dd HH:mm} UTC");
if (isCryptoAmount)
{
sb.AppendLine($"\n*Send exactly {payment.RequiredAmount:F8} {FormatCurrency(payment.Currency)} to:*");
}
else
{
sb.AppendLine($"\n*Wallet Address:*");
}
sb.AppendLine($"`{payment.WalletAddress}`");
if (!string.IsNullOrEmpty(payment.BTCPayCheckoutUrl))
{
sb.AppendLine($"\n*Alternative Payment Link:*");
sb.AppendLine(payment.BTCPayCheckoutUrl);
}
sb.AppendLine("\n⚠ *Important:*");
sb.AppendLine("• Send the exact amount shown");
sb.AppendLine("• Payment must be received before expiry");
sb.AppendLine("• Save this information before closing");
return sb.ToString();
}
public static string FormatHelp()
{
return "*Available Commands:*\n\n" +
"/start - Start shopping\n" +
"/browse - Browse categories\n" +
"/products - View all products\n" +
"/cart - View shopping cart\n" +
"/orders - View your orders\n" +
"/review - Review delivered products\n" +
"/reviews - View all product reviews\n" +
"/support - Chat with support\n" +
"/privacy - Privacy policy\n" +
"/clear - Clear shopping cart\n" +
"/cancel - Cancel current operation\n" +
"/delete - Delete all your data\n" +
"/help - Show this help message\n\n";
}
public static string FormatPrivacyPolicy()
{
return "🔒 *Privacy Policy*\n\n" +
"*Data Collection:*\n" +
"• We store minimal data necessary for orders\n" +
"• No personal identifiers are stored\n" +
"• All sessions are ephemeral by default\n\n" +
"*Data Retention:*\n" +
"• Ephemeral sessions: 30 minutes\n" +
"• Order data: As required for fulfillment\n" +
"• No tracking or analytics without consent\n\n" +
"*Your Rights:*\n" +
"• Delete all data at any time (/delete)\n" +
"• Use PGP encryption for shipping\n" +
"• Access via Tor network\n" +
"• Cryptocurrency payments only\n\n" +
"*Security:*\n" +
"• All data encrypted at rest\n" +
"• Optional Tor routing\n" +
"• No third-party tracking\n" +
"• Open source and auditable";
}
private static string FormatOrderStatus(int status)
{
return status switch
{
0 => "⏳ Pending Payment",
1 => "💰 Payment Received",
2 => "⚙️ Processing",
3 => "📦 Picking & Packing",
4 => "🚚 Shipped",
5 => "✅ Delivered",
6 => "❌ Cancelled",
7 => "💸 Refunded",
_ => $"Status {status}"
};
}
private static string FormatPaymentStatus(int status)
{
return status switch
{
0 => "⏳ Pending",
1 => "✅ Paid",
2 => "❌ Failed",
3 => "⏰ Expired",
4 => "❌ Cancelled",
_ => $"Status {status}"
};
}
private static string FormatCurrency(int currency)
{
return currency switch
{
0 => "BTC",
1 => "XMR",
2 => "USDT",
3 => "LTC",
4 => "ETH",
5 => "ZEC",
6 => "DASH",
7 => "DOGE",
_ => $"Currency {currency}"
};
}
}
}