a708727241
Build and Deploy to Kubernetes / build-and-deploy (push) Has been cancelled
- Added a wrapper div for product items in the DiscountStore and Store pages to improve layout consistency. - Implemented state management for URL synchronization and scroll restoration in both product components. - Refactored product loading logic to streamline data retrieval and improve user experience when navigating between product pages. These changes enhance the overall functionality and user experience of the product listing pages, ensuring better state management and navigation.
95 lines
3.2 KiB
C#
95 lines
3.2 KiB
C#
using Microsoft.AspNetCore.WebUtilities;
|
|
using Microsoft.Extensions.Primitives;
|
|
|
|
namespace FrontOffice.Main.Utilities;
|
|
|
|
public enum ProductSortOption
|
|
{
|
|
PriceDesc,
|
|
PriceAsc,
|
|
Newest,
|
|
Title
|
|
}
|
|
|
|
/// <summary>
|
|
/// وضعیت لیست فروشگاه در query string — فقط برای /products و /discount-store.
|
|
/// </summary>
|
|
public sealed class ShopListQueryState
|
|
{
|
|
public string Query { get; init; } = string.Empty;
|
|
public string? Sort { get; init; }
|
|
public long? CategoryId { get; init; }
|
|
public int Pages { get; init; } = 1;
|
|
|
|
public static ShopListQueryState Parse(Uri uri)
|
|
{
|
|
var q = QueryHelpers.ParseQuery(uri.Query);
|
|
return new ShopListQueryState
|
|
{
|
|
Query = GetString(q, "q") ?? string.Empty,
|
|
Sort = GetString(q, "sort"),
|
|
CategoryId = GetLong(q, "category"),
|
|
Pages = Math.Max(1, GetInt(q, "pages") ?? 1)
|
|
};
|
|
}
|
|
|
|
public string ToRelativeUrl(string path)
|
|
{
|
|
var dict = new Dictionary<string, string?>();
|
|
if (!string.IsNullOrWhiteSpace(Query))
|
|
dict["q"] = Query.Trim();
|
|
if (!string.IsNullOrWhiteSpace(Sort) && !string.Equals(Sort, "price-desc", StringComparison.OrdinalIgnoreCase))
|
|
dict["sort"] = Sort;
|
|
if (CategoryId is > 0)
|
|
dict["category"] = CategoryId.Value.ToString();
|
|
if (Pages > 1)
|
|
dict["pages"] = Pages.ToString();
|
|
|
|
return dict.Count == 0
|
|
? path
|
|
: QueryHelpers.AddQueryString(path, dict!);
|
|
}
|
|
|
|
public bool Matches(ShopListQueryState other) =>
|
|
string.Equals(Query?.Trim() ?? "", other.Query?.Trim() ?? "", StringComparison.Ordinal)
|
|
&& string.Equals(NormalizeSort(Sort), NormalizeSort(other.Sort), StringComparison.OrdinalIgnoreCase)
|
|
&& CategoryId == other.CategoryId
|
|
&& Pages == other.Pages;
|
|
|
|
public static string NormalizeSort(string? sort) =>
|
|
string.IsNullOrWhiteSpace(sort) ? "price-desc" : sort.Trim().ToLowerInvariant();
|
|
|
|
public static string ToSortKey(ProductSortOption option) => option switch
|
|
{
|
|
ProductSortOption.PriceAsc => "price-asc",
|
|
ProductSortOption.Newest => "newest",
|
|
ProductSortOption.Title => "title",
|
|
_ => "price-desc"
|
|
};
|
|
|
|
public static ProductSortOption ParseSortOption(string? sort) => NormalizeSort(sort) switch
|
|
{
|
|
"price-asc" => ProductSortOption.PriceAsc,
|
|
"newest" => ProductSortOption.Newest,
|
|
"title" => ProductSortOption.Title,
|
|
_ => ProductSortOption.PriceDesc
|
|
};
|
|
|
|
public static string ToApiSortBy(ProductSortOption option) => option switch
|
|
{
|
|
ProductSortOption.PriceAsc => "price asc",
|
|
ProductSortOption.Newest => "id desc",
|
|
ProductSortOption.Title => "title asc",
|
|
_ => "price desc"
|
|
};
|
|
|
|
private static string? GetString(Dictionary<string, StringValues> q, string key) =>
|
|
q.TryGetValue(key, out var v) ? v.FirstOrDefault() : null;
|
|
|
|
private static long? GetLong(Dictionary<string, StringValues> q, string key) =>
|
|
long.TryParse(GetString(q, key), out var n) ? n : null;
|
|
|
|
private static int? GetInt(Dictionary<string, StringValues> q, string key) =>
|
|
int.TryParse(GetString(q, key), out var n) ? n : null;
|
|
}
|