Refactor tables to Razor components

This commit is contained in:
2023-12-10 20:36:48 +00:00
parent fd05501fad
commit 8223568ed6
15 changed files with 624 additions and 417 deletions

View File

@ -2,65 +2,55 @@
@using Microsoft.EntityFrameworkCore
@layout Layout
@inject AppDbContext DbContext
@inject NavigationManager Navigation
@inject IHttpContextAccessor HttpContextAccessor
<PageTitle>Groceries &ndash; Items</PageTitle>
<div class="row">
<header class="row">
<h1 class="row__fill">Items</h1>
<SearchForm data-turbo-frame="table" data-turbo-action="advance">
<input type="hidden" name="page" value="1" />
</SearchForm>
</div>
<search title="Items">
<SearchForm data-turbo-frame="table" data-turbo-action="advance">
<input type="hidden" name="page" value="1" />
</SearchForm>
</search>
</header>
<turbo-frame id="table" target="top">
<section class="table">
<table>
<thead>
<tr>
<th scope="col" class="table__header table__header--shaded">Brand</th>
<th scope="col" class="table__header table__header--shaded" style="width: 100%">Name</th>
<th scope="col" class="table__header table__header--shaded">Last Purchased</th>
<th scope="col" class="table__header table__header--shaded">Barcode</th>
@*<th scope="col" class="table__header table__header--shaded"></th>*@
</tr>
</thead>
<tbody>
@foreach (var item in items)
{
<tr>
<td class="table__cell">@item.Brand</td>
<td class="table__cell">@item.Name</td>
<td class="table__cell">
<time datetime="@item.LastPurchasedAt?.ToString("o")">@item.LastPurchasedAt?.ToLongDateString()</time>
</td>
<td class="table__cell table__cell--icon" style="width: fit-content">@(item.HasBarcode ? "✓" : "")</td>
@*<td class="table__cell">
<a class="link" href="/items/edit/@item.Id">Edit</a>
</td>*@
</tr>
}
</tbody>
</table>
<TablePaginator Model="items" />
<Table Items="items" Pagination="pagination" HeaderClass="table__header--shaded">
<PropertyTableColumn Property="i => i.Brand" Sortable="true" />
<PropertyTableColumn Property="i => i.Name" Fill="true" Sortable="true" />
<PropertyTableColumn Property="i => i.LastPurchasedAt" Title="Last Purchased" Sortable="true">
<time datetime="@context?.ToString("o")">@context?.ToLongDateString()</time>
</PropertyTableColumn>
<PropertyTableColumn Property="i => i.HasBarcode" Title="Barcode" Align="Align.Center" Sortable="true">
<span class="icon icon--sm">@(context ? "✓" : "")</span>
</PropertyTableColumn>
@* <TemplateTableColumn>
<a class="link" href="/items/edit/@context.Id">Edit</a>
</TemplateTableColumn> *@
</Table>
<TablePaginator State="pagination" />
</section>
</turbo-frame>
@code {
[SupplyParameterFromQuery]
public int? Page { get; set; }
private record ItemModel
{
public Guid Id { get; init; }
public required string Brand { get; init; }
public required string Name { get; init; }
public bool HasBarcode { get; init; }
public DateTime? LastPurchasedAt { get; init; }
}
private IQueryable<ItemModel> items = null!;
private PaginationState pagination = new();
[SupplyParameterFromQuery]
public string? Search { get; set; }
private record ItemModel(Guid Id, string Brand, string Name, bool HasBarcode, DateTime? LastPurchasedAt);
private ListPageModel<ItemModel> items = ListPageModel.Empty<ItemModel>();
protected override async Task OnParametersSetAsync()
protected override void OnParametersSet()
{
var itemsQuery = DbContext.Items.AsQueryable();
if (!string.IsNullOrEmpty(Search))
@ -69,27 +59,23 @@
itemsQuery = itemsQuery.Where(item => EF.Functions.ILike(item.Brand + ' ' + item.Name, searchPattern));
}
items = await itemsQuery
.OrderBy(item => item.Brand)
.ThenBy(item => item.Name)
items = itemsQuery
.GroupJoin(
DbContext.ItemPurchases.Where(purchase => purchase.IsLastPurchase),
item => item.Id,
lastPurchase => lastPurchase.ItemId,
(item, lastPurchase) => new { item, lastPurchase })
purchase => purchase.ItemId,
(item, purchases) => new { item, purchases })
.SelectMany(
group => group.lastPurchase.DefaultIfEmpty(),
(group, lastPurchase) => new ItemModel(
group.item.Id,
group.item.Brand,
group.item.Name,
group.item.Barcodes.Count != 0,
lastPurchase != null ? lastPurchase.CreatedAt : null))
.ToListPageModelAsync(Page.GetValueOrDefault(), cancellationToken: HttpContextAccessor.HttpContext!.RequestAborted);
if (items.Page != Page)
{
Navigation.NavigateTo(Navigation.GetUriWithQueryParameter("page", items.Page));
}
group => group.purchases.DefaultIfEmpty(),
(group, lastPurchase) => new ItemModel
{
Id = group.item.Id,
Brand = group.item.Brand,
Name = group.item.Name,
HasBarcode = group.item.Barcodes.Count != 0,
LastPurchasedAt = lastPurchase != null ? lastPurchase.CreatedAt : null,
})
.OrderBy(item => item.Brand)
.ThenBy(item => item.Name);
}
}