Files
prefab-page-detail/Prefab.Web/Gateway/Products.cs
2025-10-27 17:39:18 -04:00

121 lines
4.6 KiB
C#

using System.Net;
using FluentValidation;
using Prefab.Domain.Exceptions;
using Prefab.Endpoints;
using Prefab.Shared.Catalog;
using Prefab.Shared.Catalog.Products;
using Prefab.Web.Client.Models.Catalog;
using Prefab.Web.Client.Models.Shared;
using Prefab.Web.Client.ViewModels.Catalog;
using Prefab.Web.Client.Services;
using UrlBuilder = Prefab.Web.UrlPolicy.UrlPolicy;
namespace Prefab.Web.Gateway;
public static class Products
{
public sealed class Endpoints : IEndpointRegistrar
{
public void MapEndpoints(IEndpointRouteBuilder endpoints)
{
endpoints.MapGet(
"/bff/catalog/categories/{slug}/models",
async (ListingService service, string slug, CancellationToken cancellationToken) =>
{
var result = await service.GetCategoryProducts(slug, cancellationToken);
var status = result.Problem?.StatusCode ?? (result.IsSuccess
? StatusCodes.Status200OK
: StatusCodes.Status500InternalServerError);
return Results.Json(result, statusCode: status);
})
.WithTags(nameof(Products));
}
}
public sealed class ListingService(IModuleClient moduleClient) : IProductListingService
{
public async Task<Result<ProductListingModel>> GetCategoryProducts(string categorySlug, CancellationToken cancellationToken)
{
ArgumentException.ThrowIfNullOrWhiteSpace(categorySlug);
try
{
var response = await moduleClient.Product.GetCategoryModels(
categorySlug.Trim(),
page: null,
pageSize: null,
sort: null,
direction: null,
cancellationToken);
var listing = MapListing(response.Result);
return Result<ProductListingModel>.Success(listing);
}
catch (ValidationException validationException)
{
var problem = ResultProblem.FromValidation(validationException);
return Result<ProductListingModel>.Failure(problem);
}
catch (DomainException domainException)
{
var problem = ResultProblem.Unexpected(domainException.Message, domainException, HttpStatusCode.UnprocessableEntity);
return Result<ProductListingModel>.Failure(problem);
}
catch (Exception exception)
{
var problem = ResultProblem.Unexpected("Failed to retrieve category products.", exception);
return Result<ProductListingModel>.Failure(problem);
}
}
private static ProductListingModel MapListing(GetCategoryModels.CategoryProductsResponse payload)
{
var category = payload.Category;
var categoryModel = new ProductCategoryModel
{
Id = category.Id,
Name = category.Name,
Slug = category.Slug,
Description = category.Description,
HeroImageUrl = category.HeroImageUrl,
Icon = category.Icon
};
var cards = payload.Products
.Select(product => new ProductCardModel
{
Id = product.Id,
Title = product.Name,
Url = UrlBuilder.BrowseProduct(product.Slug),
Slug = product.Slug,
PrimaryImageUrl = product.PrimaryImageUrl,
CategoryName = category.Name,
CategoryUrl = UrlBuilder.BrowseCategory(category.Slug),
FromPrice = product.FromPrice.HasValue
? new MoneyModel
{
Amount = product.FromPrice.Value
}
: null,
IsPriced = product.FromPrice.HasValue,
OldPrice = null,
IsOnSale = false,
Rating = 0,
ReviewCount = 0,
Badges = new List<string>(),
LastModifiedOn = product.LastModifiedOn
})
.ToList();
return new ProductListingModel
{
Category = categoryModel,
Products = cards,
Total = payload.Total,
Page = payload.Page,
PageSize = payload.PageSize
};
}
}
}