From c961dfa47a4c56028d11b2fe68f290c3f359a5d8 Mon Sep 17 00:00:00 2001 From: sysadmin Date: Fri, 3 Oct 2025 14:41:00 +0100 Subject: [PATCH] "Add-Multi-Buy-section-to-product-editor" --- .../Admin/Controllers/ProductsController.cs | 4 + .../Areas/Admin/Views/Products/Edit.cshtml | 276 ++++++++++++++++++ .../Controllers/ProductMultiBuysController.cs | 2 +- TeleBot/.claude/settings.local.json | 8 + 4 files changed, 289 insertions(+), 1 deletion(-) create mode 100644 TeleBot/.claude/settings.local.json diff --git a/LittleShop/Areas/Admin/Controllers/ProductsController.cs b/LittleShop/Areas/Admin/Controllers/ProductsController.cs index e2702c1..90ec2a6 100644 --- a/LittleShop/Areas/Admin/Controllers/ProductsController.cs +++ b/LittleShop/Areas/Admin/Controllers/ProductsController.cs @@ -94,6 +94,10 @@ public class ProductsController : Controller ViewData["ProductId"] = id; ViewData["ProductPhotos"] = product.Photos; + // Load product multi-buys + var productMultiBuys = await _productService.GetProductMultiBuysAsync(id); + ViewData["ProductMultiBuys"] = productMultiBuys; + // TODO: Add ReviewService injection and retrieve actual reviews // For now, providing mock review data for demonstration ViewData["ProductReviews"] = new[] diff --git a/LittleShop/Areas/Admin/Views/Products/Edit.cshtml b/LittleShop/Areas/Admin/Views/Products/Edit.cshtml index 4868444..697273e 100644 --- a/LittleShop/Areas/Admin/Views/Products/Edit.cshtml +++ b/LittleShop/Areas/Admin/Views/Products/Edit.cshtml @@ -163,6 +163,160 @@ + +
+
+
+ +
+
+
+

Configure quantity-based pricing (e.g., 1 for £10, 2 for £19, 3 for £25).

+ + @if (productMultiBuys != null && productMultiBuys.Any()) + { +
+ + + + + + + + + + + + + @foreach (var multiBuy in productMultiBuys.OrderBy(mb => mb.SortOrder)) + { + + + + + + + + + } + +
NameQuantityPricePer UnitStatusActions
@multiBuy.Name@multiBuy.Quantity£@multiBuy.Price.ToString("F2")£@multiBuy.PricePerUnit.ToString("F2") + @if (multiBuy.IsActive) + { + Active + } + else + { + Inactive + } + + + +
+
+ } + else + { +
+ +

No multi-buy offers configured yet.

+
+ } + + +
+
+
Add Multi-Buy Offer
+
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ +
+ +
+
+
+
+ + + +
+
+
+
+
+
+
@@ -561,6 +715,128 @@ } }); }); + + // Multi-Buy Management + const productId = '@productId'; + + // Edit multi-buy button + document.querySelectorAll('.edit-multibuy-btn').forEach(btn => { + btn.addEventListener('click', function() { + const id = this.dataset.id; + const name = this.dataset.name; + const description = this.dataset.description; + const quantity = this.dataset.quantity; + const price = this.dataset.price; + const sortorder = this.dataset.sortorder; + const isactive = this.dataset.isactive === 'True'; + + document.getElementById('multibuy-id').value = id; + document.getElementById('multibuy-name').value = name; + document.getElementById('multibuy-description').value = description; + document.getElementById('multibuy-quantity').value = quantity; + document.getElementById('multibuy-price').value = price; + document.getElementById('multibuy-sortorder').value = sortorder; + document.getElementById('multibuy-isactive').checked = isactive; + + document.getElementById('save-multibuy-btn').innerHTML = ' Update Multi-Buy'; + document.getElementById('cancel-multibuy-btn').style.display = 'inline-block'; + }); + }); + + // Cancel edit + document.getElementById('cancel-multibuy-btn').addEventListener('click', function() { + document.getElementById('multibuy-id').value = ''; + document.getElementById('multibuy-name').value = ''; + document.getElementById('multibuy-description').value = ''; + document.getElementById('multibuy-quantity').value = '1'; + document.getElementById('multibuy-price').value = ''; + document.getElementById('multibuy-sortorder').value = '0'; + document.getElementById('multibuy-isactive').checked = true; + + document.getElementById('save-multibuy-btn').innerHTML = ' Save Multi-Buy'; + this.style.display = 'none'; + }); + + // Save multi-buy + document.getElementById('save-multibuy-btn').addEventListener('click', async function() { + const multibuyId = document.getElementById('multibuy-id').value; + const name = document.getElementById('multibuy-name').value.trim(); + const description = document.getElementById('multibuy-description').value.trim(); + const quantity = parseInt(document.getElementById('multibuy-quantity').value); + const price = parseFloat(document.getElementById('multibuy-price').value); + const sortOrder = parseInt(document.getElementById('multibuy-sortorder').value); + const isActive = document.getElementById('multibuy-isactive').checked; + + if (!name || !quantity || !price) { + alert('Please fill in Name, Quantity, and Price'); + return; + } + + const data = { + name, + description, + quantity, + price, + sortOrder, + isActive + }; + + try { + let response; + if (multibuyId) { + // Update existing + response = await fetch(`/api/productmultibuys/${multibuyId}`, { + method: 'PUT', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(data) + }); + } else { + // Create new + data.productId = productId; + response = await fetch('/api/productmultibuys', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(data) + }); + } + + if (response.ok) { + location.reload(); + } else { + const error = await response.text(); + alert('Error: ' + error); + } + } catch (error) { + alert('Error saving multi-buy: ' + error.message); + } + }); + + // Delete multi-buy + document.querySelectorAll('.delete-multibuy-btn').forEach(btn => { + btn.addEventListener('click', async function() { + const id = this.dataset.id; + const name = this.dataset.name; + + if (!confirm(`Delete multi-buy "${name}"?`)) { + return; + } + + try { + const response = await fetch(`/api/productmultibuys/${id}`, { + method: 'DELETE' + }); + + if (response.ok) { + location.reload(); + } else { + const error = await response.text(); + alert('Error: ' + error); + } + } catch (error) { + alert('Error deleting multi-buy: ' + error.message); + } + }); + }); }); } \ No newline at end of file diff --git a/LittleShop/Controllers/ProductMultiBuysController.cs b/LittleShop/Controllers/ProductMultiBuysController.cs index 91199c9..99c1d49 100644 --- a/LittleShop/Controllers/ProductMultiBuysController.cs +++ b/LittleShop/Controllers/ProductMultiBuysController.cs @@ -7,7 +7,7 @@ namespace LittleShop.Controllers; [ApiController] [Route("api/[controller]")] -[Authorize(AuthenticationSchemes = "Bearer")] +[Authorize(AuthenticationSchemes = "Bearer,Cookies")] public class ProductMultiBuysController : ControllerBase { private readonly IProductService _productService; diff --git a/TeleBot/.claude/settings.local.json b/TeleBot/.claude/settings.local.json new file mode 100644 index 0000000..6627356 --- /dev/null +++ b/TeleBot/.claude/settings.local.json @@ -0,0 +1,8 @@ +{ + "outputStyle": "mr-tickles", + "permissions": { + "allow": [ + "Read(//mnt/c/Production/Source/LittleShop/**)" + ] + } +} \ No newline at end of file