Skip to content
This repository has been archived by the owner on Jul 12, 2024. It is now read-only.

Commit

Permalink
refactor: feature product
Browse files Browse the repository at this point in the history
  • Loading branch information
foxminchan committed Jun 2, 2024
1 parent e46f73e commit 22f2f07
Show file tree
Hide file tree
Showing 13 changed files with 83 additions and 60 deletions.
Original file line number Diff line number Diff line change
@@ -1,31 +1,33 @@
using MediatR;
using Microsoft.AspNetCore.Http.HttpResults;
using RookieShop.Application.Reports.DTOs;
using RookieShop.ApiService.ViewModels.Reports;
using RookieShop.Application.Reports.Queries.BestSellerProducts;
using RookieShop.Infrastructure.Endpoints.Abstractions;
using RookieShop.Infrastructure.RateLimiter;

namespace RookieShop.ApiService.Endpoints.Reports;

public sealed class BestSellerProducts(ISender sender)
: IEndpoint<Ok<List<BestSellerProductsDto>>, BestSellerProductsRequest>
: IEndpoint<Ok<List<BestSellerProductsVm>>, BestSellerProductsRequest>
{
public void MapEndpoint(IEndpointRouteBuilder app) =>
app.MapGet("/reports/best-seller-products",
async (int top) => await HandleAsync(new(top)))
.Produces<Ok<List<BestSellerProductsDto>>>()
.Produces<Ok<List<BestSellerProductsVm>>>()
.WithTags(nameof(Reports))
.WithName("Best Seller Products")
.MapToApiVersion(new(1, 0))
.RequirePerUserRateLimit();

public async Task<Ok<List<BestSellerProductsDto>>> HandleAsync(BestSellerProductsRequest request,
public async Task<Ok<List<BestSellerProductsVm>>> HandleAsync(BestSellerProductsRequest request,
CancellationToken cancellationToken = default)
{
BestSellerProductsQuery query = new(request.Top);

var result = await sender.Send(query, cancellationToken);
var data = await sender.Send(query, cancellationToken);

return TypedResults.Ok(result.Value.ToList());
var result = data.Value.ToBestSellerProductsVm();

return TypedResults.Ok(result);
}
}
1 change: 1 addition & 0 deletions src/RookieShop.ApiService/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
.AddRouting(options => options.LowercaseUrls = true)
.AddSingleton(new JsonSerializerOptions
{
WriteIndented = true,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
PropertyNameCaseInsensitive = true
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using RookieShop.Domain.Entities.ProductAggregator.ValueObjects;

namespace RookieShop.ApiService.ViewModels.Reports;

public sealed record BestSellerProductsVm(
Guid ProductId,
string? ProductName,
int TotalSoldQuantity,
ProductPrice? Price,
string? ImageUrl
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System.Text.Json;
using RookieShop.Application.Reports.DTOs;
using RookieShop.Domain.Entities.ProductAggregator.ValueObjects;

namespace RookieShop.ApiService.ViewModels.Reports;

public static class DtoToViewModelMapper
{
public static BestSellerProductsVm ToBestSellerProductsVm(this BestSellerProductsDto bestSellerProductsDto)
{
var price = JsonSerializer.Deserialize<ProductPrice>(bestSellerProductsDto.Price);

return new(
bestSellerProductsDto.ProductId,
bestSellerProductsDto.ProductName,
bestSellerProductsDto.TotalSoldQuantity,
price,
bestSellerProductsDto.ImageUrl
);
}

public static List<BestSellerProductsVm> ToBestSellerProductsVm(this IEnumerable<BestSellerProductsDto> bestSellerProductsDtos) =>
bestSellerProductsDtos.Select(ToBestSellerProductsVm).ToList();
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
namespace RookieShop.Application.Reports.DTOs;
using System.Text.Json.Serialization;

namespace RookieShop.Application.Reports.DTOs;

public sealed class BestSellerProductsDto
{
public Guid ProductId { get; set; }
public string? ProductName { get; set; }
public int TotalSoldQuantity { get; set; }
[JsonRequired]
public string Price { get; set; } = string.Empty;
public string? ImageUrl { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@
Checkout
</button>
<smart-paste-button class="w-full text-center bg-stone-600 rounded-xl py-3 px-6 font-semibold text-lg text-white transition-all duration-500 hover:bg-stone-700">
<img loading="lazy" src="~/imgs/payment/smart-paste.svg" class="h-6 inline-block mr-2 htmx-indicator" alt="Paste" asp-append-version="true" />
<img loading="lazy" src="~/imgs/payment/smart-paste.svg" class="h-6 inline-block mr-2" alt="Paste" asp-append-version="true" />
Smart Paste
</smart-paste-button>
</form>
7 changes: 6 additions & 1 deletion ui/storefront/Areas/Product/Models/Products/ProductPrice.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
namespace RookieShop.Storefront.Areas.Product.Models.Products;
using System.Text.Json.Serialization;

namespace RookieShop.Storefront.Areas.Product.Models.Products;

public sealed class ProductPrice
{
[JsonPropertyName("price")]
public decimal Price { get; set; }

[JsonPropertyName("priceSale")]
public decimal? PriceSale { get; set; }
}
15 changes: 0 additions & 15 deletions ui/storefront/Models/Report/BestSellerProduct.cs

This file was deleted.

9 changes: 0 additions & 9 deletions ui/storefront/Models/Report/BestSellerProductResponse.cs

This file was deleted.

15 changes: 13 additions & 2 deletions ui/storefront/Models/Report/BestSellerProductViewModel.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
using RookieShop.Storefront.Areas.Product.Models.Products;
using System.Text.Json.Serialization;
using RookieShop.Storefront.Areas.Product.Models.Products;

namespace RookieShop.Storefront.Models.Report;

public sealed class BestSellerProductViewModel : BestSellerProduct
public sealed class BestSellerProductViewModel
{
[JsonPropertyName("productId")] public Guid ProductId { get; set; }

[JsonPropertyName("productName")] public string? ProductName { get; set; }

[JsonPropertyName("totalSoldQuantity")]
public int TotalSoldQuantity { get; set; }

[JsonPropertyName("imageUrl")] public string? ImageUrl { get; set; }

[JsonPropertyName("price")]
public ProductPrice? Price { get; set; }
}
2 changes: 1 addition & 1 deletion ui/storefront/Services/IReportService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ namespace RookieShop.Storefront.Services;
public interface IReportService
{
[Get("/reports/best-seller-products")]
Task <List<BestSellerProductResponse>> GetBestSellerProductsAsync([Query] BestSellerProductFilterParams filterParams);
Task <List<BestSellerProductViewModel>> GetBestSellerProductsAsync([Query] BestSellerProductFilterParams filterParams);
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
@model List<RookieShop.Storefront.Models.Report.BestSellerProductViewModel>
@using System.Globalization
@using Microsoft.AspNetCore.Mvc.TagHelpers
@model List<RookieShop.Storefront.Models.Report.BestSellerProductViewModel>

@if (Model.Count == 0)
{
Expand All @@ -21,19 +23,19 @@ else
<div class="mt-4 flex justify-between">
<div>
<h3 class="text-sm text-gray-700">
<span class="font-medium hover:text-gray-800">
<a asp-area="Product"
asp-controller="Product"
asp-action="Detail"
asp-route-id="@item.ProductId"
class="font-medium hover:text-gray-800">
<span aria-hidden="true" class="absolute inset-0"></span>
@item.ProductName
</span>
</a>
</h3>
</div>
<a asp-area="Product"
asp-controller="Product"
asp-action="Detail"
asp-route-id="@item.ProductId"
class="text-sm font-medium text-gray-900 text-red-900">
Purchase
</a>
<span class="text-sm font-medium text-gray-900 text-red-900">
@item.Price?.PriceSale?.ToString("C", CultureInfo.CreateSpecificCulture("en-US"))
</span>
</div>
</div>
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
using System.Text.Json;
using Microsoft.AspNetCore.Mvc;
using RookieShop.Storefront.Areas.Product.Models.Products;
using RookieShop.Storefront.Models.Report;
using Microsoft.AspNetCore.Mvc;
using RookieShop.Storefront.Services;

namespace RookieShop.Storefront.Views.Shared.Components.FeatureProducts;
Expand All @@ -13,15 +10,6 @@ public async Task<IViewComponentResult> InvokeAsync()
{
var data = await reportService.GetBestSellerProductsAsync(new());

var result = data.Select(x => new BestSellerProductViewModel
{
ProductId = x.ProductId,
ProductName = x.ProductName,
TotalSoldQuantity = x.TotalSoldQuantity,
Price = JsonSerializer.Deserialize<ProductPrice>(x.Price),
ImageUrl = x.ImageUrl
}).ToList();

return View(result);
return View(data);
}
}

0 comments on commit 22f2f07

Please sign in to comment.