Add category browsing and product filtering with breadcrumbs
This commit is contained in:
@@ -1,7 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using FrontOffice.BFF.Products.Protobuf.Protos.Products;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
namespace FrontOffice.Main.Utilities;
|
||||
|
||||
@@ -46,7 +49,8 @@ public record ProductCategoryPathInfo(
|
||||
|
||||
public class ProductService
|
||||
{
|
||||
private readonly ConcurrentDictionary<long, Product> _cache = new();
|
||||
private readonly ConcurrentDictionary<long, CacheEntry> _cache = new();
|
||||
private static readonly TimeSpan CacheDuration = TimeSpan.FromMinutes(1);
|
||||
private readonly ProductsContract.ProductsContractClient _client;
|
||||
|
||||
public ProductService(ProductsContract.ProductsContractClient client)
|
||||
@@ -54,11 +58,11 @@ public class ProductService
|
||||
_client = client;
|
||||
}
|
||||
|
||||
public async Task<List<Product>> GetProductsAsync(string? query = null)
|
||||
public async Task<List<Product>> GetProductsAsync(string? query = null, long? categoryId = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var resp = await _client.GetAllProductsByFilterAsync(new GetAllProductsByFilterRequest
|
||||
var request = new GetAllProductsByFilterRequest
|
||||
{
|
||||
Filter = new GetAllProductsByFilterFilter
|
||||
{
|
||||
@@ -67,12 +71,19 @@ public class ProductService
|
||||
ShortInfomation = query ?? string.Empty,
|
||||
FullInformation = query ?? string.Empty
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
if (categoryId is { } value)
|
||||
{
|
||||
request.Filter.CategoryId = value ;
|
||||
}
|
||||
|
||||
var resp = await _client.GetAllProductsByFilterAsync(request);
|
||||
return MapAndCache(resp.Models);
|
||||
}
|
||||
catch
|
||||
{
|
||||
IEnumerable<Product> list = _cache.Values;
|
||||
IEnumerable<Product> list = GetValidCachedProducts();
|
||||
if (!string.IsNullOrWhiteSpace(query))
|
||||
{
|
||||
var q = query.Trim();
|
||||
@@ -87,7 +98,7 @@ public class ProductService
|
||||
|
||||
public async Task<Product?> GetByIdAsync(long id)
|
||||
{
|
||||
if (_cache.TryGetValue(id, out var cached)) return cached;
|
||||
if (TryGetCachedProduct(id, out var cached)) return cached;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -101,7 +112,7 @@ public class ProductService
|
||||
}
|
||||
catch
|
||||
{
|
||||
_cache.TryGetValue(id, out var result);
|
||||
TryGetCachedProduct(id, out var result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -123,9 +134,7 @@ public class ProductService
|
||||
Rate: m.Rate,
|
||||
RemainingCount: m.RemainingCount
|
||||
);
|
||||
if (_cache.All(a => a.Key != p.Id))
|
||||
_cache[p.Id] = p;
|
||||
|
||||
CacheProduct(p);
|
||||
|
||||
list.Add(p);
|
||||
}
|
||||
@@ -159,10 +168,42 @@ public class ProductService
|
||||
Categories = MapCategoryPaths(model.Categories)
|
||||
};
|
||||
|
||||
_cache[product.Id] = product;
|
||||
CacheProduct(product);
|
||||
return product;
|
||||
}
|
||||
|
||||
private void CacheProduct(Product product)
|
||||
{
|
||||
var entry = new CacheEntry(product, DateTime.UtcNow.Add(CacheDuration));
|
||||
_cache.AddOrUpdate(product.Id, entry, (_, _) => entry);
|
||||
}
|
||||
|
||||
private bool TryGetCachedProduct(long id, [NotNullWhen(true)] out Product? product)
|
||||
{
|
||||
if (_cache.TryGetValue(id, out var entry))
|
||||
{
|
||||
if (entry.Expiration > DateTime.UtcNow)
|
||||
{
|
||||
product = entry.Product;
|
||||
return true;
|
||||
}
|
||||
|
||||
_cache.TryRemove(id, out _);
|
||||
}
|
||||
|
||||
product = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
private IEnumerable<Product> GetValidCachedProducts()
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
return _cache.Values
|
||||
.Where(entry => entry.Expiration > now)
|
||||
.Select(entry => entry.Product);
|
||||
}
|
||||
|
||||
private sealed record CacheEntry(Product Product, DateTime Expiration);
|
||||
private static string BuildUrl(string? path) =>
|
||||
string.IsNullOrWhiteSpace(path) ? string.Empty : UrlUtility.DownloadUrl + path;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user