littleshop/LittleShop/Areas/Admin/Views/VariantCollections/Index.cshtml
sysadmin eb87148c63 Add variant collections system and enhance ProductVariant with weight/stock tracking
This commit introduces a comprehensive variant management system and enhances
the existing ProductVariant model with per-variant weight overrides and stock
tracking, integrated across Admin Panel and TeleBot.

Features Added:
- Variant Collections: Reusable variant templates (e.g., "Standard Sizes")
- Admin UI for managing variant collections (CRUD operations)
- Dynamic variant editor with JavaScript-based UI
- Per-variant weight and weight unit overrides
- Per-variant stock level tracking
- SalesLedger model for financial tracking

ProductVariant Enhancements:
- Added Weight (decimal, nullable) field for variant-specific weights
- Added WeightUnit (enum, nullable) field for variant-specific units
- Maintains backward compatibility with product-level weights

TeleBot Integration:
- Enhanced variant selection UI to display stock levels
- Shows weight information with proper unit conversion (µg, g, oz, lb, ml, L)
- Compact button format: "Medium (15 in stock, 350g)"
- Real-time stock availability display

Database Migrations:
- 20250928014850_AddVariantCollectionsAndSalesLedger
- 20250928155814_AddWeightToProductVariants

Technical Changes:
- Updated Product model to support VariantCollectionId and VariantsJson
- Extended ProductService with variant collection operations
- Enhanced OrderService to handle variant-specific pricing and weights
- Updated LittleShop.Client DTOs to match server models
- Added JavaScript dynamic variant form builder

Files Modified: 15
Files Added: 17
Lines Changed: ~2000

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-28 17:03:09 +01:00

91 lines
4.2 KiB
Plaintext

@model IEnumerable<LittleShop.DTOs.VariantCollectionDto>
@{
ViewData["Title"] = "Variant Collections";
}
<div class="row mb-4">
<div class="col">
<h1><i class="fas fa-layer-group"></i> Variant Collections</h1>
<p class="text-muted">Manage reusable variant templates for products</p>
</div>
<div class="col-auto">
<a href="@Url.Action("Create")" class="btn btn-primary">
<i class="fas fa-plus"></i> Add Collection
</a>
</div>
</div>
<div class="card">
<div class="card-body">
@if (Model.Any())
{
<div class="table-responsive">
<table class="table table-striped">
<thead>
<tr>
<th>Name</th>
<th>Properties</th>
<th>Created</th>
<th>Updated</th>
<th>Status</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
@foreach (var collection in Model)
{
<tr>
<td><strong>@collection.Name</strong></td>
<td>
@if (collection.PropertiesJson != "[]" && !string.IsNullOrWhiteSpace(collection.PropertiesJson))
{
<code class="small">@collection.PropertiesJson.Substring(0, Math.Min(50, collection.PropertiesJson.Length))@(collection.PropertiesJson.Length > 50 ? "..." : "")</code>
}
else
{
<span class="text-muted">No properties</span>
}
</td>
<td>@collection.CreatedAt.ToString("MMM dd, yyyy")</td>
<td>@collection.UpdatedAt.ToString("MMM dd, yyyy")</td>
<td>
@if (collection.IsActive)
{
<span class="badge bg-success">Active</span>
}
else
{
<span class="badge bg-danger">Inactive</span>
}
</td>
<td>
<div class="btn-group btn-group-sm">
<a href="@Url.Action("Edit", new { id = collection.Id })" class="btn btn-outline-primary">
<i class="fas fa-edit"></i>
</a>
<form method="post" action="@Url.Action("Delete", new { id = collection.Id })" class="d-inline"
onsubmit="return confirm('Are you sure you want to deactivate this collection?')">
@Html.AntiForgeryToken()
<button type="submit" class="btn btn-outline-danger">
<i class="fas fa-trash"></i>
</button>
</form>
</div>
</td>
</tr>
}
</tbody>
</table>
</div>
}
else
{
<div class="text-center py-4">
<i class="fas fa-layer-group fa-3x text-muted mb-3"></i>
<p class="text-muted">No variant collections found. <a href="@Url.Action("Create")">Create your first collection</a>.</p>
<p class="small text-muted">Variant collections define reusable property templates (e.g., "Mens Clothes" with Size and Colour properties)</p>
</div>
}
</div>
</div>