littleshop/TeleBot/TeleBot/Models/UserSession.cs
SysAdmin f12f35cc48 Implement product variant selection in TeleBot
FEATURES IMPLEMENTED:

1. Enhanced Product Display:
   - Shows multi-buy deals with pricing (e.g., "3 for £25")
   - Displays available variants grouped by type (Color, Flavor, etc.)
   - Clear visual separation between multi-buys and variants

2. Variant Selection Flow:
   - Single item: Select one variant from available options
   - Multi-buy bundles: Select individual variants for each item
   - Example: 3-pack allows choosing Red, Blue, Green individually
   - Visual feedback with checkmarks and counters

3. Smart Cart Management:
   - Tracks selected variants for each cart item
   - Supports both single variant (regular items) and multiple variants (multi-buys)
   - Unique cart entries based on product + variant combination
   - Prevents duplicate multi-buy bundles

4. User Experience Improvements:
   - Clear "Select Color/Flavor" prompts
   - Progress indicator for multi-item selection
   - Confirm button appears when selection complete
   - Clear selection option for multi-buys
   - Back navigation preserves context

TECHNICAL CHANGES:
- ProductCarouselService: Enhanced caption formatting with variants/multi-buys
- MenuBuilder: New VariantSelectionMenu with dynamic button generation
- CallbackHandler: Added handlers for selectvar, setvariant, addvariant, confirmvar
- ShoppingCart: New AddItem overload accepting Product and variant list
- CartItem: Added SelectedVariants list for multi-buy support
- UserSession: Added SelectingVariants state

This update enables customers to:
- See all available product options at a glance
- Choose specific variants when ordering
- Mix and match variants in multi-buy deals
- Get exactly what they want with clear visual feedback

Next steps: Add bot activity tracking for live dashboard

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-24 23:09:33 +01:00

104 lines
3.5 KiB
C#

using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;
namespace TeleBot.Models
{
public class UserSession
{
public string Id { get; set; } = Guid.NewGuid().ToString();
public string HashedUserId { get; set; } = string.Empty;
public SessionState State { get; set; } = SessionState.MainMenu;
// Telegram User Information (for customer creation)
public long TelegramUserId { get; set; }
public string TelegramUsername { get; set; } = string.Empty;
public string TelegramDisplayName { get; set; } = string.Empty;
public string TelegramFirstName { get; set; } = string.Empty;
public string TelegramLastName { get; set; } = string.Empty;
public ShoppingCart Cart { get; set; } = new();
public Dictionary<string, object> TempData { get; set; } = new();
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
public DateTime LastActivityAt { get; set; } = DateTime.UtcNow;
public DateTime ExpiresAt { get; set; }
public bool IsEphemeral { get; set; } = true;
public PrivacySettings Privacy { get; set; } = new();
// Order flow data (temporary)
public OrderFlowData? OrderFlow { get; set; }
public static string HashUserId(long telegramUserId, string salt = "TeleBot-Privacy-Salt")
{
using var sha256 = SHA256.Create();
var bytes = Encoding.UTF8.GetBytes($"{telegramUserId}:{salt}");
var hash = sha256.ComputeHash(bytes);
return Convert.ToBase64String(hash);
}
public bool IsExpired()
{
return DateTime.UtcNow > ExpiresAt;
}
public void UpdateActivity()
{
LastActivityAt = DateTime.UtcNow;
}
}
public class PrivacySettings
{
public bool UseEphemeralMode { get; set; } = true;
public bool UseTorOnly { get; set; } = false;
public bool DisableAnalytics { get; set; } = true;
public bool RequirePGP { get; set; } = false;
public string? PGPPublicKey { get; set; }
public bool EnableDisappearingMessages { get; set; } = true;
public int DisappearingMessageTTL { get; set; } = 30; // seconds
}
public class OrderFlowData
{
public string? IdentityReference { get; set; }
public string? ShippingName { get; set; }
public string? ShippingAddress { get; set; }
public string? ShippingCity { get; set; }
public string? ShippingPostCode { get; set; }
public string? ShippingCountry { get; set; } = "United Kingdom";
public string? Notes { get; set; }
public string? SelectedCurrency { get; set; }
public bool UsePGPEncryption { get; set; }
public OrderFlowStep CurrentStep { get; set; } = OrderFlowStep.CollectingName;
}
public enum OrderFlowStep
{
CollectingName,
CollectingAddress,
CollectingCity,
CollectingPostCode,
CollectingCountry,
CollectingNotes,
ReviewingOrder,
SelectingPaymentMethod,
ProcessingPayment,
Complete
}
public enum SessionState
{
MainMenu,
BrowsingCategories,
ViewingProducts,
ViewingProduct,
SelectingVariants,
ViewingCart,
CheckoutFlow,
ViewingOrders,
ViewingOrder,
PrivacySettings,
CustomerSupport,
Help
}
}