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> <MudTd>
<MudStack Spacing="1"> <MudStack Spacing="1">
<MudStack Row="true" Spacing="2" AlignItems="AlignItems.Center"> <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> <MudText>@context.Title</MudText>
</MudStack> </MudStack>
@if (context.Discount > 0 || !string.IsNullOrWhiteSpace(context.Created) || !string.IsNullOrWhiteSpace(context.Description)) @if (context.Discount > 0 || !string.IsNullOrWhiteSpace(context.Created) || !string.IsNullOrWhiteSpace(context.Description))
@@ -85,7 +86,8 @@
<MudStack Spacing="1"> <MudStack Spacing="1">
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center"> <MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center">
<MudStack Row="true" Spacing="2" 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> <MudText Typo="Typo.subtitle2">@item.Title</MudText>
</MudStack> </MudStack>
@if (item.Discount > 0) @if (item.Discount > 0)
@@ -99,11 +101,11 @@
{ {
<MudStack Spacing="1"> <MudStack Spacing="1">
@if (!string.IsNullOrWhiteSpace(item.Description)) @* @if (!string.IsNullOrWhiteSpace(item.Description)) *@
{ @* { *@
<MudText Typo="Typo.caption" @* <MudText Typo="Typo.caption" *@
Class="mud-text-secondary">@item.Description</MudText> @* Class="mud-text-secondary">@item.Description</MudText> *@
} @* } *@
@* @if (!string.IsNullOrWhiteSpace(item.Created)) *@ @* @if (!string.IsNullOrWhiteSpace(item.Created)) *@
@* { *@ @* { *@
@* <MudText Typo="Typo.caption" Class="mud-text-secondary">تاریخ افزودن: @item.Created</MudText> *@ @* <MudText Typo="Typo.caption" Class="mud-text-secondary">تاریخ افزودن: @item.Created</MudText> *@
@@ -151,7 +153,7 @@
OnClick="() => Navigation.NavigateTo(RouteConstants.Store.Products)">افزودن محصول OnClick="() => Navigation.NavigateTo(RouteConstants.Store.Products)">افزودن محصول
</MudButton> </MudButton>
<MudButton Variant="Variant.Filled" Color="Color.Success" OnClick="ProceedCheckout" <MudButton Variant="Variant.Filled" Color="Color.Success" OnClick="ProceedCheckout"
StartIcon="@Icons.Material.Filled.CreditCard">ادامه فرایند خرید StartIcon="@Icons.Material.Filled.CreditCard">ادامه خرید
</MudButton> </MudButton>
</MudStack> </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 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() public void Dispose()
{ {
CartService.OnChange -= StateHasChanged; CartService.OnChange -= StateHasChanged;

View File

@@ -79,16 +79,24 @@
@foreach (var item in Cart.Items) @foreach (var item in Cart.Items)
{ {
<MudListItem T="CartItem"> <MudListItem T="CartItem">
<MudStack Spacing="1" Class="w-100">
<MudStack Row="true" Justify="Justify.SpaceBetween"> <MudListItemText>
<MudText>@item.Title x @item.Quantity</MudText> <MudStack Spacing="1">
<MudText>@FormatPrice(item.LineTotal)</MudText> <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> </MudStack>
@if (item.Discount > 0) </MudListItemText>
{
<MudText Typo="Typo.caption" Class="mud-text-secondary">@($"تخفیف: {item.Discount}%")</MudText>
}
</MudStack>
</MudListItem> </MudListItem>
} }
</MudList> </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 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> <RowTemplate>
<MudTd> <MudTd>
<MudStack Row="true" Spacing="2" AlignItems="AlignItems.Center"> <MudStack Row="true" Spacing="2" AlignItems="AlignItems.Center">
<MudAvatar Image="@context.ProductThumbnailPath" Size="Size.Medium" /> <MudImage Src="@GetProductImageUrl(context.ProductThumbnailPath)" Alt="@context.ProductTitle"
<MudText>@context.ProductTitle</MudText> Width="64" Height="64" Class="product-thumb" />
<MudText>@context.ProductThumbnailPath</MudText>
</MudStack> </MudStack>
</MudTd> </MudTd>
<MudTd>@FormatPrice(context.UnitPrice.Value)</MudTd> <MudTd>@FormatPrice(context.UnitPrice.Value)</MudTd>
@@ -58,7 +59,8 @@ else
<MudPaper Class="pa-3 rounded-lg" Outlined="true"> <MudPaper Class="pa-3 rounded-lg" Outlined="true">
<MudStack Spacing="1"> <MudStack Spacing="1">
<MudStack Row="true" Spacing="2" AlignItems="AlignItems.Center"> <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> <MudText>@it.ProductTitle</MudText>
</MudStack> </MudStack>
<MudStack Row="true" Justify="Justify.SpaceBetween"> <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>@GetStatusText(context.PaymentStatus)</MudTd>
<MudTd>@FormatPrice(context.FactorDetails.Sum(s=>s.UnitPrice.Value*s.Count.Value))</MudTd> <MudTd>@FormatPrice(context.FactorDetails.Sum(s=>s.UnitPrice.Value*s.Count.Value))</MudTd>
<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> </MudTd>
</RowTemplate> </RowTemplate>
</MudTable> </MudTable>
@@ -50,7 +50,7 @@
</MudStack> </MudStack>
<MudStack Row="true" Justify="Justify.SpaceBetween"> <MudStack Row="true" Justify="Justify.SpaceBetween">
<MudText>وضعیت: @GetStatusText(o.PaymentStatus)</MudText> <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>
<MudStack Row="true" Justify="Justify.FlexEnd"> <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> <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.BFF.UserOrder.Protobuf.Protos.UserOrder;
using FrontOffice.Main.Utilities; using FrontOffice.Main.Utilities;
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
using MudBlazor;
namespace FrontOffice.Main.Pages.Store; namespace FrontOffice.Main.Pages.Store;
@@ -14,8 +16,19 @@ public partial class Orders : ComponentBase
protected override async Task OnInitializedAsync() protected override async Task OnInitializedAsync()
{ {
_loading = true; _loading = true;
_orders = await OrderService.GetOrdersAsync(); try
_loading = false; {
_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); 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 FrontOffice.BFF.UserOrder.Protobuf.Protos.UserOrder;
using Mapster;
namespace FrontOffice.Main.Utilities; namespace FrontOffice.Main.Utilities;
@@ -41,9 +42,26 @@ public class OrderService
_userOrderContractClient = userOrderContractClient; _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) 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 { width: 100%; display: flex; gap: .5rem; }
.mobile-actions-stack > * { flex: 1; } .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*/ /*#endregion*/
/*#region Profile Tiles*/ /*#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