Files
ECommerce.Module/Components/Pages/Shop/Shop.razor
T

164 lines
6.8 KiB
Plaintext

@page "/shop"
@inject ProductAPIConsumer productService
@inject CategoryAPIConsumer categoryService
@inject NavigationManager nav
@using Common
<div class="flex flex-col gap-8 pb-20">
<!-- Hero Section -->
<div class="relative w-full h-80 rounded-b-2xl overflow-hidden shadow-2xl">
<div class="absolute inset-0 bg-cover bg-center"
style="background-image: url(https://img.daisyui.com/images/stock/photo-1507358522600-9f71e620c44e.webp);">
</div>
<div class="absolute inset-0 bg-black/50 backdrop-blur-[2px]"></div>
<div class="relative z-10 h-full flex flex-col justify-center items-center text-center text-white py-12 px-6">
<h1 class="text-4xl md:text-6xl font-extrabold mb-4 tracking-tight">@Loc["Welcome_to_Our_Shop"]</h1>
<p class="text-lg md:text-xl text-gray-200 max-w-2xl">@Loc["Best_Quality_Products"]</p>
</div>
</div>
<!-- Filter Section -->
<EditForm Model="productFilter" OnValidSubmit="() => OnSearchProduct(1)"
class="bg-white dark:bg-gray-800 rounded-b-xl shadow-lg p-6 border border-gray-100 dark:border-gray-700 -mt-8">
<div class="grid grid-cols-1 lg:grid-cols-4 gap-6 items-end">
<!-- Search -->
<div class="lg:col-span-1">
<label class="block text-sm font-semibold text-gray-700 dark:text-gray-300 mb-2">@Loc["Search"]</label>
<div class="relative">
<InputText @bind-Value="productFilter.Name" placeholder="@Loc["Search_Products"]"
class="w-full pl-4 pr-10 py-3 rounded-lg border border-gray-300 focus:ring-2 focus:ring-orange-500 focus:border-orange-500 outline-none transition-all dark:bg-gray-700 dark:border-gray-600 dark:text-white" />
<button type="submit"
class="absolute right-2 top-1/2 -translate-y-1/2 p-2 text-gray-400 hover:text-orange-500">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24"
stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
</svg>
</button>
</div>
</div>
<!-- Category -->
<div class="lg:col-span-1">
<label class="block text-sm font-semibold text-gray-700 dark:text-gray-300 mb-2">@Loc["Category"]</label>
<CategoryTreeSelect @bind-Value="productFilter.CategoryId" ShowBundles="false"
Placeholder="@Loc["All_Categories"]" />
</div>
<!-- Type -->
<div class="lg:col-span-1">
<label class="block text-sm font-semibold text-gray-700 dark:text-gray-300 mb-2">@Loc["Type"]</label>
<InputSelect @bind-Value="productFilter.IsBundle"
class="w-full px-4 py-3 rounded-lg border border-gray-300 focus:ring-2 focus:ring-orange-500 focus:border-orange-500 outline-none transition-all dark:bg-gray-700 dark:border-gray-600 dark:text-white">
<option value="true">@Loc["Bundles_Only"]</option>
<option value="false">@Loc["Products_Only"]</option>
</InputSelect>
</div>
<!-- Price -->
<div class="lg:col-span-1">
<label class="block text-sm font-semibold text-gray-700 dark:text-gray-300 mb-2">@Loc["Max_Price"]</label>
<InputNumber @bind-Value="productFilter.Price" placeholder="@Loc["Max_Price"]"
class="w-full px-4 py-3 rounded-lg border border-gray-300 focus:ring-2 focus:ring-orange-500 focus:border-orange-500 outline-none transition-all dark:bg-gray-700 dark:border-gray-600 dark:text-white" />
</div>
<!-- Discount -->
<div class="lg:col-span-1">
<label class="block text-sm font-semibold text-gray-700 dark:text-gray-300 mb-2">@Loc["Min_Discount"] %</label>
<InputNumber @bind-Value="productFilter.Discount" placeholder="@Loc["Min_Discount"]"
class="w-full px-4 py-3 rounded-lg border border-gray-300 focus:ring-2 focus:ring-orange-500 focus:border-orange-500 outline-none transition-all dark:bg-gray-700 dark:border-gray-600 dark:text-white" />
</div>
<!-- Action -->
<div class="lg:col-span-1">
<button type="submit"
class="w-full py-3 bg-orange-600 hover:bg-orange-700 text-white font-semibold rounded-lg shadow-md transition-colors duration-200">
@Loc["Apply_Filters"]
</button>
</div>
</div>
</EditForm>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 w-full h-full gap-5 p-5 md:p-12 lg:p-20">
@foreach (var product in products)
{
@if (product.IsBundle)
{
<BundleComp Bundle="product" />
}
else
{
<ProductComp4 Product="product" />
}
}
</div>
<PaginationComp OnSearch="OnSearchProduct" PaginationModel="pagination"></PaginationComp>
</div>
@code {
public Pagination pagination { get; set; } = new() { CurrentPage = 1, PageSize = 15 };
public ProductFilter productFilter { get; set; } = new ProductFilter();
List<ProductVM> products = new List<ProductVM>();
[Parameter, SupplyParameterFromQuery]
public string? CategoryId { get; set; }
[Parameter, SupplyParameterFromQuery]
public bool? IsBundle { get; set; }
protected async override Task OnParametersSetAsync()
{
bool changed = false;
if (!string.IsNullOrEmpty(CategoryId) && Guid.TryParse(CategoryId, out var categoryGuid))
{
productFilter.CategoryId = categoryGuid;
changed = true;
}
if (IsBundle.HasValue)
{
productFilter.IsBundle = IsBundle.Value;
changed = true;
}
if (changed)
{
await OnSearchProduct();
}
}
protected override void OnInitialized()
{
// Redirect to add IsBundle=true parameter if not present
if (!IsBundle.HasValue)
{
var uri = nav.GetUriWithQueryParameter("IsBundle", true);
nav.NavigateTo(uri, forceLoad: false);
}
}
protected async override Task OnInitializedAsync()
{
if (string.IsNullOrEmpty(CategoryId))
{
await OnSearchProduct();
}
}
async Task OnSearchProduct(int pageNumber = 1)
{
pagination.CurrentPage = pageNumber;
var result = await productService.FetchProduct(productFilter, pagination);
products = result.Item1;
pagination.ItemsCount = result.Item2;
}
}