Update order pages with error handling and improved product images

This commit is contained in:
masoodafar-web
2025-11-28 13:35:26 +03:30
parent 12d19f966c
commit 48dadf007a
11 changed files with 89 additions and 26 deletions

View File

@@ -30,7 +30,8 @@
<MudTd>
<MudStack Spacing="1">
<MudStack Row="true" Spacing="2" AlignItems="AlignItems.Center">
<MudAvatar Image="@context.ImageUrl" Size="Size.Medium"/>
<MudImage Src="@GetProductImageUrl(context.ImageUrl)" Alt="@context.Title"
Width="64" Height="64" Class="product-thumb" />
<MudText>@context.Title</MudText>
</MudStack>
@if (context.Discount > 0 || !string.IsNullOrWhiteSpace(context.Created) || !string.IsNullOrWhiteSpace(context.Description))
@@ -85,7 +86,8 @@
<MudStack Spacing="1">
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center">
<MudStack Row="true" Spacing="2" AlignItems="AlignItems.Center">
<MudAvatar Image="@item.ImageUrl"/>
<MudImage Src="@GetProductImageUrl(item.ImageUrl)" Alt="@item.Title"
Width="50" Height="50" Class="rounded-circle" />
<MudText Typo="Typo.subtitle2">@item.Title</MudText>
</MudStack>
@if (item.Discount > 0)
@@ -99,11 +101,11 @@
{
<MudStack Spacing="1">
@if (!string.IsNullOrWhiteSpace(item.Description))
{
<MudText Typo="Typo.caption"
Class="mud-text-secondary">@item.Description</MudText>
}
@* @if (!string.IsNullOrWhiteSpace(item.Description)) *@
@* { *@
@* <MudText Typo="Typo.caption" *@
@* Class="mud-text-secondary">@item.Description</MudText> *@
@* } *@
@* @if (!string.IsNullOrWhiteSpace(item.Created)) *@
@* { *@
@* <MudText Typo="Typo.caption" Class="mud-text-secondary">تاریخ افزودن: @item.Created</MudText> *@
@@ -151,7 +153,7 @@
OnClick="() => Navigation.NavigateTo(RouteConstants.Store.Products)">افزودن محصول
</MudButton>
<MudButton Variant="Variant.Filled" Color="Color.Success" OnClick="ProceedCheckout"
StartIcon="@Icons.Material.Filled.CreditCard">ادامه فرایند خرید
StartIcon="@Icons.Material.Filled.CreditCard">ادامه خرید
</MudButton>
</MudStack>
}

View File

@@ -46,6 +46,9 @@ public partial class Cart : ComponentBase, IDisposable
private static string FormatPrice(long price) => string.Format("{0:N0} ", price);
private static string GetProductImageUrl(string? imageUrl)
=> string.IsNullOrWhiteSpace(imageUrl) ? "/images/product-placeholder.svg" : imageUrl;
public void Dispose()
{
CartService.OnChange -= StateHasChanged;

View File

@@ -79,16 +79,24 @@
@foreach (var item in Cart.Items)
{
<MudListItem T="CartItem">
<MudStack Spacing="1" Class="w-100">
<MudStack Row="true" Justify="Justify.SpaceBetween">
<MudText>@item.Title x @item.Quantity</MudText>
<MudText>@FormatPrice(item.LineTotal)</MudText>
<MudListItemText>
<MudStack Spacing="1">
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center">
<MudImage Src="@GetProductImageUrl(item.ImageUrl)" Alt="@item.Title"
Width="48" Height="48" Class="rounded-circle" />
<MudText Typo="Typo.subtitle2">@item.Title</MudText>
<MudText Typo="Typo.subtitle2">@FormatPrice(item.LineTotal)</MudText>
</MudStack>
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center">
<MudText Typo="Typo.caption" Class="mud-text-secondary">تعداد: @item.Quantity</MudText>
@if (item.Discount > 0)
{
<MudText Typo="Typo.caption" Class="mud-text-secondary">@($"تخفیف: {item.Discount}%")</MudText>
}
</MudStack>
</MudStack>
@if (item.Discount > 0)
{
<MudText Typo="Typo.caption" Class="mud-text-secondary">@($"تخفیف: {item.Discount}%")</MudText>
}
</MudStack>
</MudListItemText>
</MudListItem>
}
</MudList>

View File

@@ -90,4 +90,7 @@ public partial class CheckoutSummary : ComponentBase
}
private static string FormatPrice(long price) => string.Format("{0:N0} تومان", price);
private static string GetProductImageUrl(string? imageUrl)
=> string.IsNullOrWhiteSpace(imageUrl) ? "/images/product-placeholder.svg" : imageUrl;
}

View File

@@ -40,8 +40,9 @@ else
<RowTemplate>
<MudTd>
<MudStack Row="true" Spacing="2" AlignItems="AlignItems.Center">
<MudAvatar Image="@context.ProductThumbnailPath" Size="Size.Medium" />
<MudText>@context.ProductTitle</MudText>
<MudImage Src="@GetProductImageUrl(context.ProductThumbnailPath)" Alt="@context.ProductTitle"
Width="64" Height="64" Class="product-thumb" />
<MudText>@context.ProductThumbnailPath</MudText>
</MudStack>
</MudTd>
<MudTd>@FormatPrice(context.UnitPrice.Value)</MudTd>
@@ -58,7 +59,8 @@ else
<MudPaper Class="pa-3 rounded-lg" Outlined="true">
<MudStack Spacing="1">
<MudStack Row="true" Spacing="2" AlignItems="AlignItems.Center">
<MudAvatar Image="@it.ProductThumbnailPath" />
<MudImage Src="@GetProductImageUrl(it.ProductThumbnailPath)" Alt="@it.ProductTitle"
Width="64" Height="64" Class="product-thumb" />
<MudText>@it.ProductTitle</MudText>
</MudStack>
<MudStack Row="true" Justify="Justify.SpaceBetween">

View File

@@ -42,5 +42,8 @@ public partial class OrderDetail : ComponentBase
_ => "نامشخص",
};
}
private static string GetProductImageUrl(string? imageUrl)
=> string.IsNullOrWhiteSpace(imageUrl) ? "/images/product-placeholder.svg" : UrlUtility.DownloadUrl+imageUrl;
}

View File

@@ -32,7 +32,7 @@
<MudTd>@GetStatusText(context.PaymentStatus)</MudTd>
<MudTd>@FormatPrice(context.FactorDetails.Sum(s=>s.UnitPrice.Value*s.Count.Value))</MudTd>
<MudTd>
<MudButton Variant="Variant.Text" Href="@($"{RouteConstants.Store.OrderDetail}{context}")" StartIcon="@Icons.Material.Filled.Receipt">جزئیات</MudButton>
<MudButton Variant="Variant.Text" Href="@($"{RouteConstants.Store.OrderDetail}{context.Id}")" StartIcon="@Icons.Material.Filled.Receipt">جزئیات</MudButton>
</MudTd>
</RowTemplate>
</MudTable>
@@ -50,7 +50,7 @@
</MudStack>
<MudStack Row="true" Justify="Justify.SpaceBetween">
<MudText>وضعیت: @GetStatusText(o.PaymentStatus)</MudText>
<MudText Color="Color.Primary">@FormatPrice(o.FactorDetails.Sum(s=>s.UnitPrice.Value*s.Count.Value)))</MudText>
<MudText Color="Color.Primary">@FormatPrice(o.FactorDetails.Sum(s=>s.UnitPrice.Value*s.Count.Value))</MudText>
</MudStack>
<MudStack Row="true" Justify="Justify.FlexEnd">
<MudButton Size="Size.Small" Variant="Variant.Outlined" Href="@($"{RouteConstants.Store.OrderDetail}{o.Id}")" StartIcon="@Icons.Material.Filled.Receipt">جزئیات</MudButton>

View File

@@ -1,6 +1,8 @@
using System;
using FrontOffice.BFF.UserOrder.Protobuf.Protos.UserOrder;
using FrontOffice.Main.Utilities;
using Microsoft.AspNetCore.Components;
using MudBlazor;
namespace FrontOffice.Main.Pages.Store;
@@ -14,8 +16,19 @@ public partial class Orders : ComponentBase
protected override async Task OnInitializedAsync()
{
_loading = true;
_orders = await OrderService.GetOrdersAsync();
_loading = false;
try
{
_orders = await OrderService.GetOrdersAsync();
}
catch (Exception ex)
{
Snackbar.Add($"خطا در بارگذاری سفارش‌ها: {ex.Message}", Severity.Error);
_orders = new List<GetUserOrderResponse>();
}
finally
{
_loading = false;
}
}
private static string FormatPrice(long price) => string.Format("{0:N0} تومان", price);

View File

@@ -1,4 +1,5 @@
using FrontOffice.BFF.UserOrder.Protobuf.Protos.UserOrder;
using Mapster;
namespace FrontOffice.Main.Utilities;
@@ -41,9 +42,26 @@ public class OrderService
_userOrderContractClient = userOrderContractClient;
}
public Task<List<GetUserOrderResponse>> GetOrdersAsync()
public async Task<List<GetUserOrderResponse>> GetOrdersAsync()
{
return Task.FromResult(_orders.OrderByDescending(o => o.PaymentDate).ToList());
var result = await _userOrderContractClient.GetAllUserOrderByFilterAsync(new());
if (result != null && result.Models.Count > 0)
{
foreach (var item in result.Models)
{
var order = new GetUserOrderResponse();
if (_orders.All(a => a.Id != item.Id))
{
TypeAdapterConfig.GlobalSettings.NewConfig<GetUserOrderResponseFactorDetail, GetUserOrderResponseFactorDetail>()
.Map(dest => dest.ProductThumbnailPath, src => src.ProductThumbnailPath);
order= item.Adapt<GetUserOrderResponse>();
order.FactorDetails.AddRange(item.FactorDetails.Adapt<List<GetUserOrderResponseFactorDetail>>());
_orders.Add(order);
}
}
}
return _orders.OrderByDescending(o => o.PaymentDate).ToList();
}
public async Task<GetUserOrderResponse?> GetOrderAsync(long id)

View File

@@ -383,6 +383,12 @@ html, body {
.mobile-actions-stack { width: 100%; display: flex; gap: .5rem; }
.mobile-actions-stack > * { flex: 1; }
}
.product-thumb {
border-radius: 12px;
object-fit: cover;
display: block;
box-shadow: 0 2px 6px rgba(0,0,0,.08);
}
/*#endregion*/
/*#region Profile Tiles*/

View File

@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 128 128">
<rect x="1" y="1" width="126" height="126" rx="14" ry="14" fill="#f7f9fc" stroke="#d5dde5" stroke-width="2" />
<path d="M28 84l22-26 18 20 14-18 18 24" fill="none" stroke="#a0b4c8" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" />
<circle cx="46" cy="44" r="10" fill="#dfe7ef" />
</svg>

After

Width:  |  Height:  |  Size: 398 B