Update product service and detail view with gallery support
This commit is contained in:
@@ -1,9 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using FrontOffice.Main.Utilities;
|
||||
|
||||
namespace FrontOffice.Main.Pages.Store;
|
||||
|
||||
public partial class ProductDetail : ComponentBase
|
||||
public partial class ProductDetail : ComponentBase, IDisposable
|
||||
{
|
||||
[Inject] private ProductService ProductService { get; set; } = default!;
|
||||
[Inject] private CartService Cart { get; set; } = default!;
|
||||
@@ -13,19 +16,151 @@ public partial class ProductDetail : ComponentBase
|
||||
private Product? _product;
|
||||
private bool _loading;
|
||||
private int _qty = 1;
|
||||
private const int MinQty = 1;
|
||||
private const int MaxQty = 20;
|
||||
private IReadOnlyList<ProductGalleryImage> _galleryItems = Array.Empty<ProductGalleryImage>();
|
||||
private ProductGalleryImage? _selectedGalleryImage;
|
||||
private long TotalPrice => (_product?.Price ?? 0) * _qty;
|
||||
private bool HasDiscount => _product is { Discount: > 0 and < 100 };
|
||||
|
||||
private long? OriginalPrice => HasDiscount && _product is not null
|
||||
? (long)Math.Round(_product.Price / (1 - (_product.Discount / 100m)))
|
||||
: null;
|
||||
|
||||
private CartItem? CurrentCartItem => _product is null
|
||||
? null
|
||||
: Cart.Items.FirstOrDefault(i => i.ProductId == _product.Id);
|
||||
|
||||
private bool IsInCart => CurrentCartItem is not null;
|
||||
private int CurrentCartQuantity => CurrentCartItem?.Quantity ?? 0;
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
_loading = true;
|
||||
_product = await ProductService.GetByIdAsync(id);
|
||||
_loading = false;
|
||||
if (_product is not null)
|
||||
{
|
||||
_galleryItems = BuildGalleryItems(_product);
|
||||
_selectedGalleryImage = _galleryItems.FirstOrDefault();
|
||||
_qty = Math.Clamp(CurrentCartItem?.Quantity ?? _qty, MinQty, MaxQty);
|
||||
}
|
||||
else
|
||||
{
|
||||
_galleryItems = Array.Empty<ProductGalleryImage>();
|
||||
}
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
Cart.OnChange += HandleCartChanged;
|
||||
}
|
||||
|
||||
private async Task AddToCart()
|
||||
{
|
||||
if (_product is null) return;
|
||||
await Cart.Add(_product, _qty);
|
||||
await Cart.Add(_product, 1);
|
||||
}
|
||||
|
||||
private async Task RemoveFromCart()
|
||||
{
|
||||
if (_product is null) return;
|
||||
_qty--;
|
||||
await Cart.UpdateQuantity(CurrentCartItem.ProductId, _qty);
|
||||
}
|
||||
|
||||
private void IncreaseLocalQty()
|
||||
{
|
||||
if (_qty < MaxQty)
|
||||
{
|
||||
_qty++;
|
||||
}
|
||||
}
|
||||
|
||||
private void DecreaseLocalQty()
|
||||
{
|
||||
if (_qty > MinQty)
|
||||
{
|
||||
_qty--;
|
||||
}
|
||||
}
|
||||
|
||||
// private async Task IncreaseCartQuantityAsync()
|
||||
// {
|
||||
// if (_product is null || CurrentCartItem is null) return;
|
||||
// var target = Math.Min(CurrentCartItem.Quantity + 1, MaxQty);
|
||||
// if (target != CurrentCartItem.Quantity)
|
||||
// {
|
||||
// await Cart.UpdateQuantity(_product.Id, target);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private async Task RemoveFromCartAsync()
|
||||
// {
|
||||
// if (CurrentCartItem is null) return;
|
||||
// await Cart.Remove(CurrentCartItem.cartId);
|
||||
// }
|
||||
|
||||
private void HandleCartChanged()
|
||||
{
|
||||
if (_product is null) return;
|
||||
_qty = Math.Clamp(CurrentCartItem?.Quantity ?? MinQty, MinQty, MaxQty);
|
||||
InvokeAsync(StateHasChanged);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Cart.OnChange -= HandleCartChanged;
|
||||
}
|
||||
|
||||
private static string FormatPrice(long price) => string.Format("{0:N0} تومان", price);
|
||||
}
|
||||
|
||||
private static IReadOnlyList<ProductGalleryImage> BuildGalleryItems(Product product)
|
||||
{
|
||||
if (product.Gallery is { Count: > 0 })
|
||||
{
|
||||
var result = new List<ProductGalleryImage>();
|
||||
result.Add(new ProductGalleryImage(0, 0, product.Title, product.ImageUrl, product.ImageUrl));
|
||||
result.AddRange(product.Gallery.Where(x => !string.IsNullOrWhiteSpace(x.ImageUrl)).ToList());
|
||||
return result;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(product.ImageUrl))
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
new ProductGalleryImage(0, 0, product.Title, product.ImageUrl, product.ImageUrl)
|
||||
};
|
||||
}
|
||||
|
||||
return Array.Empty<ProductGalleryImage>();
|
||||
}
|
||||
|
||||
private string MainImageUrl => _selectedGalleryImage?.ImageUrl
|
||||
?? _galleryItems.FirstOrDefault()?.ImageUrl
|
||||
?? _product?.ImageUrl
|
||||
?? string.Empty;
|
||||
|
||||
private string MainImageAlt => _selectedGalleryImage?.Title ?? _product?.Title ?? "تصویر محصول";
|
||||
|
||||
private string GetThumbnailUrl(ProductGalleryImage item)
|
||||
=> string.IsNullOrWhiteSpace(item.ThumbnailUrl) ? item.ImageUrl : item.ThumbnailUrl;
|
||||
|
||||
private string GetThumbnailBorder(ProductGalleryImage item)
|
||||
=> item == _selectedGalleryImage ? "2px solid rgba(30, 136, 229, 0.85)" : "1px solid rgba(0,0,0,0.12)";
|
||||
|
||||
private string GetThumbnailShadow(ProductGalleryImage item)
|
||||
=> item == _selectedGalleryImage ? "0 0 0 2px rgba(30, 136, 229, 0.25)" : "none";
|
||||
|
||||
private string GetThumbnailStyle(ProductGalleryImage item)
|
||||
=>
|
||||
$"width:76px;height:76px;object-fit:cover;border:{GetThumbnailBorder(item)};box-shadow:{GetThumbnailShadow(item)};border-radius:0.5rem;";
|
||||
|
||||
private void SelectGalleryImage(ProductGalleryImage item)
|
||||
{
|
||||
if (_selectedGalleryImage == item) return;
|
||||
_selectedGalleryImage = item;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user