Files
midrandbooks/MidrandBookshop/Components/Pages/ProductView.razor
T
Khwezi Mngoma 7a1a7566d6
continuous-integration/drone/pr Build is passing
Stable running home page with product view
2026-05-30 19:06:14 +02:00

126 lines
5.5 KiB
Plaintext

@page "/product/{BookId:long}"
@rendermode InteractiveServer
<div class="product-container">
@if (IsLoading)
{
<div class="text-center py-5">
<div class="spinner-border text-dark" role="status">
<span class="visually-hidden">Loading product details...</span>
</div>
<p class="text-muted mt-2">Loading curated details...</p>
</div>
}
else if (CurrentProduct == null)
{
<div class="text-center py-5 animate-fade-in">
<svg class="text-muted mb-3" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
<circle cx="12" cy="12" r="10" />
<line x1="12" y1="8" x2="12" y2="12" />
<line x1="12" y1="16" x2="12.01" y2="16" />
</svg>
<h2 class="h5 text-dark fw-medium">Artifact Not Found</h2>
<p class="text-muted small">The requested book could not be found in our current catalog.</p>
<button class="btn btn-dark btn-sm rounded-pill px-4 mt-2" @onclick='() => Navigation.NavigateTo("/")'>Return to Books</button>
</div>
}
else
{
<nav class="breadcrumb">
<span @onclick='() => Navigation.NavigateTo("/")' class="crumb-link">Books</span>
<span class="crumb-separator">/</span>
<span class="crumb-current">@CurrentProduct.Name</span>
</nav>
<div class="product-layout">
<div class="gallery-section">
<div class="main-image-wrapper">
@if (!string.IsNullOrWhiteSpace(ActiveImageUrl))
{
<img src="@ActiveImageUrl" alt="@CurrentProduct.Name" class="main-image" />
}
else
{
<div class="book-spine-fallback-large bg-dark d-flex align-items-center justify-content-center text-center p-4 text-white-50 shadow-sm">
<div>
<span class="fw-semibold tracking-wider d-block">@PrimaryCategory.ToUpper()</span>
<span class="opacity-50 small" style="font-size: 0.65rem;">CURATED EDITION</span>
</div>
</div>
}
<div class="format-badges">
@if (CurrentProduct.Enabled)
{
<span class="badge badge-physical">Physical Book</span>
}
<span class="badge badge-ebook">In Stock</span>
</div>
</div>
@if (Thumbnails.Count > 1)
{
<div class="thumbnail-grid">
@foreach (var img in Thumbnails)
{
var currentImg = img;
<div class="thumbnail-wrapper @(ActiveImageUrl == currentImg ? "active" : "")"
@onclick="() => ActiveImageUrl = currentImg">
<img src="@currentImg" alt="Catalog gallery thumbnail" />
</div>
}
</div>
}
</div>
<div class="details-section">
<div class="meta-header">
<span class="author-name">@AuthorName</span>
<div class="rating-stars">
@for (int i = 1; i <= 5; i++)
{
<span class="star @(i <= 4 ? "filled" : "")">★</span>
}
<span class="rating-text">(4.8)</span>
</div>
</div>
<h1 class="product-title">@CurrentProduct.Name</h1>
<div class="product-price">R @LivePrice.ToString("N2")</div>
<div class="purchase-actions">
<div class="quantity-picker">
<button @onclick="DecreaseQty" class="qty-btn">-</button>
<span class="qty-val">@Quantity</span>
<button @onclick="IncreaseQty" class="qty-btn">+</button>
</div>
<button class="btn-add-to-cart" @onclick="HandleAddToCart">
Add to Cart
</button>
</div>
<hr class="divider" />
@if (!string.IsNullOrWhiteSpace(CurrentProduct.Description))
{
<div class="info-block">
<h3>Description</h3>
<p class="description-text">@CurrentProduct.Description</p>
</div>
}
<div class="info-block author-bio-card">
<h3>About the Author</h3>
<p class="author-bio">
@(string.IsNullOrWhiteSpace(CurrentProduct.Metadata?.Manufacturer)
? "Details regarding this publisher/author are maintained inside our curated archives."
: $"{CurrentProduct.Metadata.Manufacturer} is globally recognized for their direct contribution to this specific genre spectrum.")
</p>
<button class="btn-text-link" @onclick="ViewAllAuthorBooks">
View all books by @AuthorName →
</button>
</div>
</div>
</div>
}
</div>