Add Products gRPC client and update ProductService for fetching products
This commit is contained in:
@@ -75,6 +75,8 @@ public static class ConfigureServices
|
|||||||
services.AddScoped(CreateAuthenticatedClient<UserContract.UserContractClient>);
|
services.AddScoped(CreateAuthenticatedClient<UserContract.UserContractClient>);
|
||||||
services.AddScoped(CreateAuthenticatedClient<UserAddressContract.UserAddressContractClient>);
|
services.AddScoped(CreateAuthenticatedClient<UserAddressContract.UserAddressContractClient>);
|
||||||
services.AddScoped(CreateAuthenticatedClient<UserOrderContract.UserOrderContractClient>);
|
services.AddScoped(CreateAuthenticatedClient<UserOrderContract.UserOrderContractClient>);
|
||||||
|
// Products gRPC
|
||||||
|
services.AddScoped(CreateAuthenticatedClient<FrontOffice.BFF.Products.Protobuf.Protos.Products.ProductsContract.ProductsContractClient>);
|
||||||
services.AddScoped(CreateAuthenticatedClient<TransactionContract.TransactionContractClient>);
|
services.AddScoped(CreateAuthenticatedClient<TransactionContract.TransactionContractClient>);
|
||||||
|
|
||||||
return services;
|
return services;
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
<PackageReference Include="Foursat.FrontOffice.BFF.User.Protobuf" Version="0.0.116" />
|
<PackageReference Include="Foursat.FrontOffice.BFF.User.Protobuf" Version="0.0.116" />
|
||||||
<PackageReference Include="Foursat.FrontOffice.BFF.UserAddress.Protobuf" Version="0.0.114" />
|
<PackageReference Include="Foursat.FrontOffice.BFF.UserAddress.Protobuf" Version="0.0.114" />
|
||||||
<PackageReference Include="Foursat.FrontOffice.BFF.UserOrder.Protobuf" Version="0.0.112" />
|
<PackageReference Include="Foursat.FrontOffice.BFF.UserOrder.Protobuf" Version="0.0.112" />
|
||||||
|
<PackageReference Include="FrontOffice.BFF.Products.Protobuf" Version="0.0.11" />
|
||||||
<PackageReference Include="MudBlazor" Version="8.14.0" />
|
<PackageReference Include="MudBlazor" Version="8.14.0" />
|
||||||
<PackageReference Include="Blazored.LocalStorage" Version="4.5.0" />
|
<PackageReference Include="Blazored.LocalStorage" Version="4.5.0" />
|
||||||
<PackageReference Include="Mapster" Version="7.4.0" />
|
<PackageReference Include="Mapster" Version="7.4.0" />
|
||||||
|
|||||||
@@ -33,11 +33,24 @@ else
|
|||||||
<MudText Typo="Typo.body1" Class="mud-text-secondary">@_product.Description</MudText>
|
<MudText Typo="Typo.body1" Class="mud-text-secondary">@_product.Description</MudText>
|
||||||
<MudDivider Class="my-2" />
|
<MudDivider Class="my-2" />
|
||||||
<MudText Typo="Typo.h5" Color="Color.Primary">@FormatPrice(_product.Price)</MudText>
|
<MudText Typo="Typo.h5" Color="Color.Primary">@FormatPrice(_product.Price)</MudText>
|
||||||
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="2" Class="mobile-actions-stack">
|
|
||||||
<MudNumericField T="int" @bind-Value="_qty" Min="1" Max="20" Immediate="true" HideSpinButtons="true" Class="qty-input" />
|
<!-- Desktop/tablet actions -->
|
||||||
<MudButton Variant="Variant.Filled" Color="Color.Primary" StartIcon="@Icons.Material.Filled.AddShoppingCart" OnClick="AddToCart">افزودن به سبد</MudButton>
|
<MudHidden Breakpoint="Breakpoint.MdAndUp" Invert="true">
|
||||||
<MudButton Variant="Variant.Outlined" Color="Color.Secondary" OnClick="() => Navigation.NavigateTo(RouteConstants.Store.Cart)">مشاهده سبد</MudButton>
|
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="2">
|
||||||
</MudStack>
|
<MudNumericField T="int" @bind-Value="_qty" Min="1" Max="20" Immediate="true" HideSpinButtons="true" Style="max-width:120px" />
|
||||||
|
<MudButton Variant="Variant.Filled" Color="Color.Primary" StartIcon="@Icons.Material.Filled.AddShoppingCart" OnClick="AddToCart">افزودن به سبد</MudButton>
|
||||||
|
<MudButton Variant="Variant.Outlined" Color="Color.Secondary" OnClick="() => Navigation.NavigateTo(RouteConstants.Store.Cart)">مشاهده سبد</MudButton>
|
||||||
|
</MudStack>
|
||||||
|
</MudHidden>
|
||||||
|
|
||||||
|
<!-- Mobile actions: stacked and full-width -->
|
||||||
|
<MudHidden Breakpoint="Breakpoint.MdAndUp">
|
||||||
|
<MudStack Spacing="2">
|
||||||
|
<MudNumericField T="int" @bind-Value="_qty" Min="1" Max="20" Immediate="true" HideSpinButtons="true" Class="w-100-mobile" />
|
||||||
|
<MudButton Class="w-100-mobile" Variant="Variant.Filled" Color="Color.Primary" StartIcon="@Icons.Material.Filled.AddShoppingCart" OnClick="AddToCart">افزودن به سبد</MudButton>
|
||||||
|
<MudButton Class="w-100-mobile" Variant="Variant.Outlined" Color="Color.Secondary" OnClick="() => Navigation.NavigateTo(RouteConstants.Store.Cart)">مشاهده سبد</MudButton>
|
||||||
|
</MudStack>
|
||||||
|
</MudHidden>
|
||||||
</MudStack>
|
</MudStack>
|
||||||
</MudItem>
|
</MudItem>
|
||||||
</MudGrid>
|
</MudGrid>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
|
using FrontOffice.BFF.Products.Protobuf.Protos.Products;
|
||||||
|
|
||||||
namespace FrontOffice.Main.Utilities;
|
namespace FrontOffice.Main.Utilities;
|
||||||
|
|
||||||
@@ -15,30 +16,76 @@ public class ProductService
|
|||||||
new(5, "فشارسنج دیجیتال", "فشارسنج بازویی دیجیتال با حافظه داخلی.", "/images/store/bp-monitor.jpg", 1259000)
|
new(5, "فشارسنج دیجیتال", "فشارسنج بازویی دیجیتال با حافظه داخلی.", "/images/store/bp-monitor.jpg", 1259000)
|
||||||
};
|
};
|
||||||
|
|
||||||
private readonly ConcurrentDictionary<long, Product> _products = new();
|
private readonly ConcurrentDictionary<long, Product> _cache = new();
|
||||||
|
private readonly ProductsContract.ProductsContractClient _client;
|
||||||
|
|
||||||
public ProductService()
|
public ProductService(ProductsContract.ProductsContractClient client)
|
||||||
{
|
{
|
||||||
foreach (var p in _seed) _products[p.Id] = p;
|
_client = client;
|
||||||
|
foreach (var p in _seed) _cache[p.Id] = p;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<List<Product>> GetProductsAsync(string? query = null)
|
public async Task<List<Product>> GetProductsAsync(string? query = null)
|
||||||
{
|
{
|
||||||
IEnumerable<Product> list = _products.Values.OrderBy(p => p.Id);
|
try
|
||||||
if (!string.IsNullOrWhiteSpace(query))
|
|
||||||
{
|
{
|
||||||
query = query.Trim();
|
var resp = await _client.GetAllProductsByFilterAsync(new GetAllProductsByFilterRequest
|
||||||
list = list.Where(p =>
|
{
|
||||||
p.Title.Contains(query, StringComparison.OrdinalIgnoreCase) ||
|
Filter = new GetAllProductsByFilterFilter
|
||||||
p.Description.Contains(query, StringComparison.OrdinalIgnoreCase));
|
{
|
||||||
|
Title = query ?? string.Empty,
|
||||||
|
Description = query ?? string.Empty,
|
||||||
|
ShortInfomation = query ?? string.Empty,
|
||||||
|
FullInformation = query ?? string.Empty
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return MapAndCache(resp.Models);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
IEnumerable<Product> list = _cache.Values;
|
||||||
|
if (!string.IsNullOrWhiteSpace(query))
|
||||||
|
{
|
||||||
|
var q = query.Trim();
|
||||||
|
list = list.Where(p => p.Title.Contains(q, StringComparison.OrdinalIgnoreCase) || p.Description.Contains(q, StringComparison.OrdinalIgnoreCase));
|
||||||
|
}
|
||||||
|
return list.OrderBy(p => p.Id).ToList();
|
||||||
}
|
}
|
||||||
return Task.FromResult(list.ToList());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<Product?> GetByIdAsync(long id)
|
public async Task<Product?> GetByIdAsync(long id)
|
||||||
{
|
{
|
||||||
_products.TryGetValue(id, out var result);
|
if (_cache.TryGetValue(id, out var cached)) return cached;
|
||||||
return Task.FromResult(result);
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// No single-get endpoint exposed: fetch list and pick
|
||||||
|
var resp = await _client.GetAllProductsByFilterAsync(new GetAllProductsByFilterRequest { Filter = new GetAllProductsByFilterFilter() });
|
||||||
|
var list = MapAndCache(resp.Models);
|
||||||
|
return list.FirstOrDefault(x => x.Id == id);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
_cache.TryGetValue(id, out var result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Product> MapAndCache(Google.Protobuf.Collections.RepeatedField<GetAllProductsByFilterResponseModel> models)
|
||||||
|
{
|
||||||
|
var list = new List<Product>();
|
||||||
|
foreach (var m in models)
|
||||||
|
{
|
||||||
|
var p = new Product(
|
||||||
|
Id: m.Id,
|
||||||
|
Title: m.Title ?? string.Empty,
|
||||||
|
Description: m.Description ?? string.Empty,
|
||||||
|
ImageUrl: string.IsNullOrWhiteSpace(m.ImagePath) ? string.Empty : UrlUtility.DownloadUrl + m.ImagePath,
|
||||||
|
Price: m.Price
|
||||||
|
);
|
||||||
|
_cache[p.Id] = p;
|
||||||
|
list.Add(p);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user