using System; using System.Collections.Generic; using System.Linq; using Microsoft.AspNetCore.Components; using FrontOffice.Main.Utilities; using MudBlazor; namespace FrontOffice.Main.Pages.Store; public partial class ProductDetail : ComponentBase, IDisposable { [Inject] private ProductService ProductService { get; set; } = default!; [Inject] private CartService Cart { get; set; } = default!; [Inject] private VATService VAT { get; set; } = default!; [Inject] private GuestActionGate GuestGate { get; set; } = default!; [Parameter] public long id { get; set; } private Product? _product; private bool _loading; private int _qty = 1; private const int MinQty = 1; // حداکثر تعداد قابل خرید بر اساس موجودی انبار private int MaxQty => _product?.RemainingCount > 0 ? _product.RemainingCount : 0; // آیا محصول موجود است private bool IsInStock => _product is not null && _product.RemainingCount > 0; private IReadOnlyList _galleryItems = Array.Empty(); private IReadOnlyList _categoryPaths = Array.Empty(); private ProductGalleryImage? _selectedGalleryImage; private readonly List _breadcrumbItems = new(); 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() { } protected override async Task OnInitializedAsync() { // لود سبد خرید (فقط اگر کاربر لاگین کرده باشد) await Cart.EnsureInitializedAsync(); Cart.OnChange += HandleCartChanged; _loading = true; _product = await ProductService.GetByIdAsync(id); _loading = false; if (_product is not null) { _galleryItems = BuildGalleryItems(_product); _selectedGalleryImage = _galleryItems.FirstOrDefault(); _categoryPaths = _product.Categories; UpdateBreadcrumb(); _qty = Math.Clamp(CurrentCartItem?.Quantity ?? _qty, MinQty, MaxQty); } else { _galleryItems = Array.Empty(); _categoryPaths = Array.Empty(); _breadcrumbItems.Clear(); } StateHasChanged(); await base.OnInitializedAsync(); } protected override async Task OnAfterRenderAsync(bool firstRender) { await base.OnAfterRenderAsync(firstRender); if (firstRender) { // بارگذاری نرخ VAT await VAT.LoadAsync(); } } private async Task AddToCart() { if (_product is null) return; var product = _product; await GuestGate.RunAsync(() => Cart.Add(product, 1)); } private async Task RemoveFromCart() { if (_product is null) return; await GuestGate.RunAsync(async () => { _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 string FormatPrice(long price) => $"{VAT.AddVAT(price):N0} تومان"; private string FormatPriceWithoutVAT(long price) => $"{price:N0} تومان"; private static IReadOnlyList BuildGalleryItems(Product product) { if (product.Gallery is { Count: > 0 }) { var result = new List(); 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(); } 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; } private void UpdateBreadcrumb() { _breadcrumbItems.Clear(); if (_product is null) { return; } _breadcrumbItems.Add(new BreadcrumbItem("خانه", href: RouteConstants.Store.Products)); var nodes = _categoryPaths .OrderByDescending(path => path.Nodes.Count) .FirstOrDefault()?.Nodes ?? Array.Empty(); foreach (var node in nodes) { var target = $"{RouteConstants.Store.Products}?category={node.Id}"; _breadcrumbItems.Add(new BreadcrumbItem(node.Title, href: target)); } // _breadcrumbItems.Add(new BreadcrumbItem(_product.Title, href: null, disabled: true)); } private void NavigateToCategory(ProductCategoryPathInfo path) { var target = $"{RouteConstants.Store.Products}?category={path.CategoryId}"; Navigation.NavigateTo(target); } private string GetCategoryLabel(ProductCategoryPathInfo path) => path.DisplayLabel; }