341 lines
13 KiB
C#
341 lines
13 KiB
C#
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 LittleShop*\n\n" +
|
||
"Your privacy is our priority. All sessions are ephemeral by default.\n\n" +
|
||
"How can I help you today?";
|
||
}
|
||
|
||
return "🔒 *Welcome to LittleShop - Privacy First E-Commerce*\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" +
|
||
"• Tor support available\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");
|
||
|
||
foreach (var category in categories)
|
||
{
|
||
sb.AppendLine($"• *{category.Name}*");
|
||
if (!string.IsNullOrEmpty(category.Description))
|
||
{
|
||
sb.AppendLine($" _{category.Description}_");
|
||
}
|
||
}
|
||
|
||
sb.AppendLine("\nSelect a category to browse products:");
|
||
|
||
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 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 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}`");
|
||
}
|
||
sb.AppendLine($" Amount: {payment.RequiredAmount}");
|
||
}
|
||
}
|
||
|
||
return sb.ToString();
|
||
}
|
||
|
||
public static string FormatPayment(CryptoPayment payment)
|
||
{
|
||
var sb = new StringBuilder();
|
||
|
||
sb.AppendLine($"💰 *Payment Instructions*\n");
|
||
sb.AppendLine($"*Currency:* {FormatCurrency(payment.Currency)}");
|
||
sb.AppendLine($"*Amount:* `{payment.RequiredAmount}`");
|
||
sb.AppendLine($"*Status:* {FormatPaymentStatus(payment.Status)}");
|
||
sb.AppendLine($"*Expires:* {payment.ExpiresAt:yyyy-MM-dd HH:mm} UTC");
|
||
|
||
sb.AppendLine($"\n*Send exactly {payment.RequiredAmount} {FormatCurrency(payment.Currency)} to:*");
|
||
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 products\n" +
|
||
"/cart - View shopping cart\n" +
|
||
"/orders - View your orders\n" +
|
||
"/privacy - Privacy settings\n" +
|
||
"/pgpkey - Set PGP public key\n" +
|
||
"/ephemeral - Toggle ephemeral mode\n" +
|
||
"/delete - Delete all your data\n" +
|
||
"/tor - Get Tor onion address\n" +
|
||
"/help - Show this help message\n\n" +
|
||
"*Privacy Features:*\n" +
|
||
"• All data is ephemeral by default\n" +
|
||
"• Optional PGP encryption for shipping\n" +
|
||
"• No personal data stored\n" +
|
||
"• Anonymous order references\n" +
|
||
"• Cryptocurrency payments only";
|
||
}
|
||
|
||
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}"
|
||
};
|
||
}
|
||
}
|
||
} |