Refactor tables to Razor components
This commit is contained in:
@ -2,7 +2,6 @@
|
||||
@using Microsoft.EntityFrameworkCore
|
||||
|
||||
@layout Layout
|
||||
|
||||
@inject AppDbContext DbContext
|
||||
|
||||
<PageTitle>Groceries – New Transaction</PageTitle>
|
||||
@ -14,57 +13,45 @@
|
||||
</div>
|
||||
|
||||
<form method="post">
|
||||
<div class="card form-field">
|
||||
<section class="card form-field">
|
||||
<div class="card__header row">
|
||||
<h2 class="row__fill">Items</h2>
|
||||
<a class="button button--primary" href="/transactions/new/items/new" autofocus data-turbo-frame="modal">New item</a>
|
||||
<a class="button button--primary" href="/transactions/new/items/new" autofocus data-turbo-frame="modal">
|
||||
New item
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="card__content card__content--table">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" class="table__header" style="width: 100%">Name</th>
|
||||
<th scope="col" class="table__header">Price</th>
|
||||
<th scope="col" class="table__header"><abbr title="Quantity">Qty</abbr></th>
|
||||
<th scope="col" class="table__header">Amount</th>
|
||||
<th scope="col" class="table__header"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var item in Transaction.Items)
|
||||
{
|
||||
<tr>
|
||||
<td class="table__cell table__cell--compact">
|
||||
@itemNames.GetValueOrDefault(item.ItemId)
|
||||
</td>
|
||||
<td class="table__cell table__cell--compact table__cell--numeric">
|
||||
@item.Price.ToString("c")
|
||||
</td>
|
||||
<td class="table__cell table__cell--compact table__cell--numeric">
|
||||
@item.Quantity
|
||||
</td>
|
||||
<td class="table__cell table__cell--compact table__cell--numeric">
|
||||
@item.Amount.ToString("c")
|
||||
</td>
|
||||
<td class="table__cell table__cell--compact">
|
||||
<a class="link" href="/transactions/new/items/edit/@item.ItemId" data-turbo-frame="modal">Edit</a>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<Table Items="Transaction.Items.AsQueryable()" CellClass="table__cell--compact">
|
||||
<ChildContent>
|
||||
<TemplateTableColumn Title="Name" Fill="true" Context="item">
|
||||
@itemNames.GetValueOrDefault(item.ItemId)
|
||||
</TemplateTableColumn>
|
||||
<PropertyTableColumn Property="i => i.Price" Format="c" />
|
||||
<PropertyTableColumn Property="i => i.Quantity">
|
||||
<HeaderContent>
|
||||
<abbr title="Quantity">Qty</abbr>
|
||||
</HeaderContent>
|
||||
</PropertyTableColumn>
|
||||
<PropertyTableColumn Property="i => i.Amount" Format="c" />
|
||||
<TemplateTableColumn Context="item">
|
||||
<a class="link" href="/transactions/new/items/edit/@item.ItemId" data-turbo-frame="modal">
|
||||
Edit
|
||||
</a>
|
||||
</TemplateTableColumn>
|
||||
</ChildContent>
|
||||
<FooterContent>
|
||||
<tr>
|
||||
<td class="table__cell table__cell--compact table__cell--total" colspan="3">Subtotal</td>
|
||||
<td class="table__cell table__cell--compact table__cell--numeric table__cell--total">
|
||||
<td class="table__cell table__cell--compact table__cell--total table__cell--align-end">
|
||||
@Transaction.Items.Sum(item => item.Amount).ToString("c")
|
||||
</td>
|
||||
<td class="table__cell table__cell--compact"></td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</FooterContent>
|
||||
</Table>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="row">
|
||||
<button class="button button--primary" type="submit" disabled="@(Transaction.Items.Count == 0)">Next</button>
|
||||
@ -73,12 +60,12 @@
|
||||
</form>
|
||||
|
||||
@code {
|
||||
[Parameter]
|
||||
public required Transaction Transaction { get; set; }
|
||||
|
||||
private string store = string.Empty;
|
||||
private Dictionary<Guid, string> itemNames = new();
|
||||
|
||||
[Parameter]
|
||||
public required Transaction Transaction { get; set; }
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
store = await DbContext.Stores
|
||||
|
@ -2,7 +2,6 @@
|
||||
@using Microsoft.EntityFrameworkCore
|
||||
|
||||
@layout Layout
|
||||
|
||||
@inject AppDbContext DbContext
|
||||
|
||||
<PageTitle>Groceries – New Transaction</PageTitle>
|
||||
@ -14,55 +13,42 @@
|
||||
</div>
|
||||
|
||||
<form method="post">
|
||||
<div class="card form-field">
|
||||
<div class="card__header row">
|
||||
<section class="card form-field">
|
||||
<header class="card__header row">
|
||||
<h2 class="row__fill">Promotions</h2>
|
||||
<a class="button button--primary" href="/transactions/new/promotions/new" autofocus data-turbo-frame="modal">
|
||||
New promotion
|
||||
</a>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="card__content card__content--table">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" class="table__header" style="width: 100%">Name</th>
|
||||
<th scope="col" class="table__header">Items</th>
|
||||
<th scope="col" class="table__header">Amount</th>
|
||||
<th scope="col" class="table__header"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var promotion in Transaction.Promotions)
|
||||
{
|
||||
<tr>
|
||||
<td class="table__cell table__cell--compact">
|
||||
@promotion.Name
|
||||
</td>
|
||||
<td class="table__cell table__cell--compact table__cell--numeric">
|
||||
@promotion.Items.Sum(item => Transaction.Items.Single(i => i.ItemId == item.Id).Quantity)
|
||||
</td>
|
||||
<td class="table__cell table__cell--compact table__cell--numeric">
|
||||
@((-promotion.Amount).ToString("c"))
|
||||
</td>
|
||||
<td class="table__cell table__cell--compact">
|
||||
<a class="link" href="/transactions/new/promotions/edit/@promotion.Id" data-turbo-frame="modal">Edit</a>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<Table Items="Transaction.Promotions.AsQueryable()" CellClass="table__cell--compact">
|
||||
<ChildContent>
|
||||
<PropertyTableColumn Property="p => p.Name" Fill="true" />
|
||||
<TemplateTableColumn Title="Items" Align="Align.End" Context="promotion">
|
||||
@promotion.Items.Sum(item => Transaction.Items.Single(i => i.ItemId == item.Id).Quantity)
|
||||
</TemplateTableColumn>
|
||||
<PropertyTableColumn Property="p => p.Amount" Context="amount">
|
||||
@((-amount).ToString("c"))
|
||||
</PropertyTableColumn>
|
||||
<TemplateTableColumn Context="promotion">
|
||||
<a class="link" href="/transactions/new/promotions/edit/@promotion.Id" data-turbo-frame="modal">
|
||||
Edit
|
||||
</a>
|
||||
</TemplateTableColumn>
|
||||
</ChildContent>
|
||||
<FooterContent>
|
||||
<tr>
|
||||
<td class="table__cell table__cell--compact table__cell--total" colspan="2">Total</td>
|
||||
<td class="table__cell table__cell--compact table__cell--numeric table__cell--total">
|
||||
<td class="table__cell table__cell--compact table__cell--total table__cell--align-end">
|
||||
@Transaction.Total.ToString("c")
|
||||
</td>
|
||||
<td class="table__cell table__cell--compact"></td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</FooterContent>
|
||||
</Table>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="row">
|
||||
<button class="button button--primary" type="submit" disabled="@(Transaction.Items.Count == 0)">Save</button>
|
||||
@ -71,11 +57,11 @@
|
||||
</form>
|
||||
|
||||
@code {
|
||||
private string store = string.Empty;
|
||||
|
||||
[Parameter]
|
||||
public required Transaction Transaction { get; set; }
|
||||
|
||||
private string store = string.Empty;
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
store = await DbContext.Stores
|
||||
|
@ -1,139 +1,58 @@
|
||||
@using Groceries.Data
|
||||
@layout Layout
|
||||
|
||||
@layout Layout
|
||||
@inject AppDbContext DbContext
|
||||
@inject NavigationManager Navigation
|
||||
@inject IHttpContextAccessor HttpContextAccessor
|
||||
|
||||
<PageTitle>Groceries – Transactions</PageTitle>
|
||||
|
||||
<div class="row">
|
||||
<header class="row">
|
||||
<h1 class="row__fill">Transactions</h1>
|
||||
<a class="button button--primary form-field" href="/transactions/new">New transaction</a>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section class="table">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" class="table__header table__header--shaded table__header--sortable">
|
||||
<a href="@GetColumnHeaderUri("date")" data-dir="@GetColumnSortDirection("date")">
|
||||
Date
|
||||
</a>
|
||||
</th>
|
||||
<th scope="col" class="table__header table__header--shaded" style="width: 100%">Store</th>
|
||||
<th scope="col" class="table__header table__header--shaded table__header--sortable">
|
||||
<a href="@GetColumnHeaderUri("items")" data-dir="@GetColumnSortDirection("items")">
|
||||
Items
|
||||
</a>
|
||||
</th>
|
||||
<th scope="col" class="table__header table__header--shaded table__header--sortable">
|
||||
<a href="@GetColumnHeaderUri("amount")" data-dir="@GetColumnSortDirection("amount")">
|
||||
Amount
|
||||
</a>
|
||||
</th>
|
||||
@* <th scope="col" class="table__header table__header--shaded"></th> *@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var transaction in transactions)
|
||||
{
|
||||
<tr>
|
||||
<td class="table__cell">
|
||||
<time datetime="@transaction.CreatedAt.ToString("o")">@transaction.CreatedAt.ToLongDateString()</time>
|
||||
</td>
|
||||
<td class="table__cell">@transaction.Store</td>
|
||||
<td class="table__cell table__cell--numeric">@transaction.TotalItems</td>
|
||||
<td class="table__cell table__cell--numeric">@transaction.TotalAmount.ToString("c")</td>
|
||||
@*<td class="table__cell">View</td>*@
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
<TablePaginator Model="transactions" />
|
||||
<Table Items="transactions" Pagination="pagination" HeaderClass="table__header--shaded">
|
||||
<PropertyTableColumn Property="t => t.CreatedAt" Title="Date" Sortable="true" Context="createdAt">
|
||||
<time datetime="@createdAt.ToString("o")">@createdAt.ToLongDateString()</time>
|
||||
</PropertyTableColumn>
|
||||
<PropertyTableColumn Property="t => t.Store" Fill="true" Sortable="true" />
|
||||
<PropertyTableColumn Property="t => t.TotalItems" Title="Items" Sortable="true" />
|
||||
<PropertyTableColumn Property="t => t.TotalAmount" Title="Amount" Format="c" Sortable="true" />
|
||||
@* <TemplateTableColumn>
|
||||
<a class="link" href="/transactions/@context.Id">View</a>
|
||||
</TemplateTableColumn> *@
|
||||
</Table>
|
||||
<TablePaginator State="pagination" />
|
||||
</section>
|
||||
|
||||
@code {
|
||||
[SupplyParameterFromQuery]
|
||||
public int? Page { get; set; }
|
||||
|
||||
[SupplyParameterFromQuery(Name = "sort")]
|
||||
public string? SortColumnName { get; set; }
|
||||
|
||||
[SupplyParameterFromQuery(Name = "dir")]
|
||||
public string? SortDirection { get; set; }
|
||||
|
||||
private record TransactionModel(Guid Id, DateTime CreatedAt, string Store, decimal TotalAmount, int TotalItems);
|
||||
|
||||
private ListPageModel<TransactionModel> transactions = ListPageModel.Empty<TransactionModel>();
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
private record TransactionModel
|
||||
{
|
||||
var transactionsQuery = DbContext.Transactions
|
||||
public Guid Id { get; init; }
|
||||
public DateTime CreatedAt { get; init; }
|
||||
public required string Store { get; init; }
|
||||
public decimal TotalAmount { get; init; }
|
||||
public int TotalItems { get; init; }
|
||||
}
|
||||
|
||||
private IQueryable<TransactionModel> transactions = null!;
|
||||
private PaginationState pagination = new();
|
||||
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
transactions = DbContext.Transactions
|
||||
.Join(
|
||||
DbContext.TransactionTotals,
|
||||
transaction => transaction.Id,
|
||||
transactionTotal => transactionTotal.TransactionId,
|
||||
(transaction, transactionTotal) => new
|
||||
(transaction, transactionTotal) => new TransactionModel
|
||||
{
|
||||
transaction.Id,
|
||||
transaction.CreatedAt,
|
||||
Id = transaction.Id,
|
||||
CreatedAt = transaction.CreatedAt,
|
||||
Store = string.Concat(transaction.Store!.Retailer!.Name, " ", transaction.Store.Name),
|
||||
TotalAmount = transactionTotal.Total,
|
||||
TotalItems = transaction.Items.Sum(item => item.Quantity),
|
||||
});
|
||||
|
||||
transactionsQuery = SortColumnName?.ToLowerInvariant() switch
|
||||
{
|
||||
"date" when SortDirection == "desc" => transactionsQuery.OrderByDescending(transaction => transaction.CreatedAt),
|
||||
"amount" when SortDirection == "desc" => transactionsQuery.OrderByDescending(transaction => transaction.TotalAmount),
|
||||
"items" when SortDirection == "desc" => transactionsQuery.OrderByDescending(transaction => transaction.TotalItems),
|
||||
"date" => transactionsQuery.OrderBy(transaction => transaction.CreatedAt),
|
||||
"amount" => transactionsQuery.OrderBy(transaction => transaction.TotalAmount),
|
||||
"items" => transactionsQuery.OrderBy(transaction => transaction.TotalItems),
|
||||
_ => transactionsQuery.OrderByDescending(transaction => transaction.CreatedAt),
|
||||
};
|
||||
|
||||
transactions = await transactionsQuery
|
||||
.Select(transaction => new TransactionModel(
|
||||
transaction.Id,
|
||||
transaction.CreatedAt,
|
||||
transaction.Store,
|
||||
transaction.TotalAmount,
|
||||
transaction.TotalItems))
|
||||
.ToListPageModelAsync(Page.GetValueOrDefault(), cancellationToken: HttpContextAccessor.HttpContext!.RequestAborted);
|
||||
|
||||
if (transactions.Page != Page)
|
||||
{
|
||||
Navigation.NavigateTo(Navigation.GetUriWithQueryParameter("page", transactions.Page));
|
||||
}
|
||||
}
|
||||
|
||||
private string GetColumnHeaderUri(string name)
|
||||
{
|
||||
var nextSortDirecton = name == SortColumnName
|
||||
? SortDirection switch
|
||||
{
|
||||
null or "" => "asc",
|
||||
"asc" => "desc",
|
||||
_ => null,
|
||||
}
|
||||
: "asc";
|
||||
|
||||
return Navigation.GetUriWithQueryParameters(new Dictionary<string, object?>
|
||||
{
|
||||
{ "sort", nextSortDirecton != null ? name : null },
|
||||
{ "dir", nextSortDirecton },
|
||||
{ "page", 1 },
|
||||
});
|
||||
}
|
||||
|
||||
private string? GetColumnSortDirection(string name)
|
||||
{
|
||||
return SortDirection switch
|
||||
{
|
||||
"asc" or "desc" when name == SortColumnName => SortDirection,
|
||||
_ => null,
|
||||
};
|
||||
})
|
||||
.OrderByDescending(transaction => transaction.CreatedAt);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user