Implement product multi-buys and variants system
Major restructuring of product variations: - Renamed ProductVariation to ProductMultiBuy for quantity-based pricing (e.g., "3 for £25") - Added new ProductVariant model for string-based options (colors, flavors) - Complete separation of multi-buy pricing from variant selection Features implemented: - Multi-buy deals with automatic price-per-unit calculation - Product variants for colors/flavors/sizes with stock tracking - TeleBot checkout supports both multi-buys and variant selection - Shopping cart correctly calculates multi-buy bundle prices - Order system tracks selected variants and multi-buy choices - Real-time bot activity monitoring with SignalR - Public bot directory page with QR codes for Telegram launch - Admin dashboard shows multi-buy and variant metrics Technical changes: - Updated all DTOs, services, and controllers - Fixed cart total calculation for multi-buy bundles - Comprehensive test coverage for new functionality - All existing tests passing with new features Database changes: - Migrated ProductVariations to ProductMultiBuys - Added ProductVariants table - Updated OrderItems to track variants 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
150
LittleShop/Views/BotDirectory/Index.cshtml
Normal file
150
LittleShop/Views/BotDirectory/Index.cshtml
Normal file
@@ -0,0 +1,150 @@
|
||||
@model List<LittleShop.Controllers.BotDirectoryDto>
|
||||
@{
|
||||
ViewData["Title"] = "Bot Directory";
|
||||
Layout = "_PublicLayout";
|
||||
}
|
||||
|
||||
<div class="container mt-4">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h1 class="display-4 text-center mb-4">
|
||||
<i class="bi bi-robot"></i> Shop Assistant Bots
|
||||
</h1>
|
||||
<p class="text-center text-muted mb-5">
|
||||
Connect with our shopping assistant bots on Telegram. Scan the QR code or click the username to start chatting!
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row g-4">
|
||||
@foreach (var bot in Model)
|
||||
{
|
||||
<div class="col-md-6 col-lg-4">
|
||||
<div class="card h-100 shadow-sm bot-card">
|
||||
<div class="card-header bg-gradient text-white" style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<h5 class="mb-0">
|
||||
<i class="bi bi-robot"></i> @bot.Name
|
||||
</h5>
|
||||
<span class="badge bg-@bot.GetBadgeColor()">@bot.Type</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body">
|
||||
<div class="text-center mb-3">
|
||||
@if (!string.IsNullOrEmpty(bot.TelegramUsername))
|
||||
{
|
||||
<img src="/bots/qr/@bot.Id" alt="QR Code for @bot.Name" class="img-fluid qr-code" style="max-width: 200px;" />
|
||||
|
||||
<div class="mt-3">
|
||||
<a href="https://t.me/@bot.TelegramUsername" target="_blank" class="btn btn-primary btn-lg">
|
||||
<i class="bi bi-telegram"></i> @@@bot.TelegramUsername
|
||||
</a>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="alert alert-warning">
|
||||
<i class="bi bi-exclamation-triangle"></i> Bot configuration pending
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
@if (!string.IsNullOrEmpty(bot.Description))
|
||||
{
|
||||
<p class="text-muted">@bot.Description</p>
|
||||
}
|
||||
|
||||
@if (!string.IsNullOrEmpty(bot.PersonalityName))
|
||||
{
|
||||
<p class="mb-2">
|
||||
<small class="text-muted">
|
||||
<i class="bi bi-person-badge"></i> Personality: <strong>@bot.PersonalityName</strong>
|
||||
</small>
|
||||
</p>
|
||||
}
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center mt-3">
|
||||
<span class="badge bg-@bot.GetStatusColor()">
|
||||
<i class="bi bi-circle-fill"></i> @bot.GetStatusBadge()
|
||||
</span>
|
||||
<small class="text-muted">
|
||||
Since @bot.CreatedAt.ToString("MMM dd, yyyy")
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (!Model.Any())
|
||||
{
|
||||
<div class="col-12">
|
||||
<div class="alert alert-info text-center">
|
||||
<h4 class="alert-heading">No Bots Available</h4>
|
||||
<p>There are currently no active bots in the directory. Please check back later!</p>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="row mt-5">
|
||||
<div class="col-12">
|
||||
<div class="card bg-light">
|
||||
<div class="card-body text-center">
|
||||
<h5 class="card-title">How to Connect</h5>
|
||||
<ol class="text-start" style="max-width: 600px; margin: 0 auto;">
|
||||
<li>Open Telegram on your mobile device</li>
|
||||
<li>Scan the QR code with your camera or click the bot username</li>
|
||||
<li>Press "Start" to begin chatting with the bot</li>
|
||||
<li>Browse products, add items to cart, and checkout securely</li>
|
||||
</ol>
|
||||
<hr>
|
||||
<p class="text-muted mb-0">
|
||||
<i class="bi bi-shield-check"></i> All transactions are secure and encrypted
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.bot-card {
|
||||
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
||||
border: none;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.bot-card:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 10px 30px rgba(0,0,0,0.15) !important;
|
||||
}
|
||||
|
||||
.qr-code {
|
||||
border: 4px solid #f8f9fa;
|
||||
border-radius: 8px;
|
||||
padding: 10px;
|
||||
background: white;
|
||||
}
|
||||
|
||||
.badge {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
@@keyframes pulse {
|
||||
0% {
|
||||
box-shadow: 0 0 0 0 rgba(102, 126, 234, 0.7);
|
||||
}
|
||||
70% {
|
||||
box-shadow: 0 0 0 10px rgba(102, 126, 234, 0);
|
||||
}
|
||||
100% {
|
||||
box-shadow: 0 0 0 0 rgba(102, 126, 234, 0);
|
||||
}
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
animation: pulse 2s infinite;
|
||||
}
|
||||
</style>
|
||||
67
LittleShop/Views/Shared/_PublicLayout.cshtml
Normal file
67
LittleShop/Views/Shared/_PublicLayout.cshtml
Normal file
@@ -0,0 +1,67 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>@ViewData["Title"] - LittleShop</title>
|
||||
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
|
||||
<link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">
|
||||
<i class="bi bi-shop"></i> LittleShop
|
||||
</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse" aria-controls="navbarSupportedContent"
|
||||
aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
|
||||
<ul class="navbar-nav flex-grow-1">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" href="/bots">
|
||||
<i class="bi bi-robot"></i> Bot Directory
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" href="/api">
|
||||
<i class="bi bi-code-slash"></i> API
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="Admin" asp-controller="Account" asp-action="Login">
|
||||
<i class="bi bi-box-arrow-in-right"></i> Admin Login
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<div class="container">
|
||||
<main role="main" class="pb-3">
|
||||
@RenderBody()
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<footer class="border-top footer text-muted">
|
||||
<div class="container text-center">
|
||||
© @DateTime.Now.Year - LittleShop - Powered by Bots
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script src="~/lib/jquery/dist/jquery.min.js"></script>
|
||||
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="~/js/site.js" asp-append-version="true"></script>
|
||||
@await RenderSectionAsync("Scripts", required: false)
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user