All checks were successful
Docker Image CI / build (push) Successful in 8m8s
124 lines
5.8 KiB
Plaintext
124 lines
5.8 KiB
Plaintext
@using Groceries.Data
|
|
@using Microsoft.EntityFrameworkCore
|
|
|
|
@inject IDbContextFactory<AppDbContext> DbContextFactory
|
|
|
|
<form method="post" @attributes="AdditionalAttributes">
|
|
@* Ensure form action/method are used for implicit submission instead of barcode button *@
|
|
<button type="submit" hidden></button>
|
|
|
|
<div data-controller="transaction-item-form">
|
|
<div class="form-field" data-transaction-item-form-target="barcodeFormField" hidden>
|
|
<label class="form-field__label" for="transactionItemBarcode">Barcode</label>
|
|
<div class="form-field__control input">
|
|
<input type="hidden" name="barcodeFormat" value="@barcode?.Format" data-transaction-item-form-target="barcodeFormat" />
|
|
<input class="input__control" id="transactionItemBarcode" name="barcodeData" value="@barcode?.BarcodeData" data-transaction-item-form-target="barcodeData" />
|
|
<button class="input__addon button" type="submit" formmethod="get" formnovalidate data-action="transaction-item-form#scanBarcode" data-transaction-item-form-target="barcodeButton">
|
|
@* Barcode scanner icon *@
|
|
<svg class="icon icon--sm" xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M40-120v-200h80v120h120v80H40Zm680 0v-80h120v-120h80v200H720ZM160-240v-480h80v480h-80Zm120 0v-480h40v480h-40Zm120 0v-480h80v480h-80Zm120 0v-480h120v480H520Zm160 0v-480h40v480h-40Zm80 0v-480h40v480h-40ZM40-640v-200h200v80H120v120H40Zm800 0v-120H720v-80h200v200h-80Z" /></svg>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<fieldset class="form-field">
|
|
<legend class="form-field__label">Item</legend>
|
|
<div class="form-field__control input">
|
|
<input class="input__control flex-2" name="brand" value="@selectedItem?.Brand" placeholder="Brand" list="itemBrands" autocomplete="off" required autofocus data-action="transaction-item-form#filterNames transaction-item-form#setPriceAndQuantity" data-transaction-item-form-target="brand" />
|
|
<input class="input__control flex-5" name="name" value="@selectedItem?.Name" placeholder="Name" list="itemNames" autocomplete="off" required data-action="transaction-item-form#setPriceAndQuantity" />
|
|
|
|
<datalist id="itemBrands">
|
|
@foreach (var item in items.DistinctBy(item => item.Brand))
|
|
{
|
|
<option value="@item.Brand" />
|
|
}
|
|
</datalist>
|
|
|
|
<datalist id="itemNames">
|
|
@foreach (var item in items)
|
|
{
|
|
<option value="@item.Name" data-transaction-item-form-target="option" data-brand="@item.Brand" data-price="@item.Price" data-quantity="@(unit == null ? (int?)item.Quantity : item.Quantity)" />
|
|
}
|
|
</datalist>
|
|
</div>
|
|
</fieldset>
|
|
|
|
<div class="form-field">
|
|
<label class="form-field__label" for="transactionItemPrice">
|
|
Price @if (unit != null) { <text>(per @unit)</text> }
|
|
</label>
|
|
<div class="form-field__control input">
|
|
@*<span class="input__inset">@CultureInfo.CurrentCulture.NumberFormat.CurrencySymbol</span>*@
|
|
<input class="input__control" id="transactionItemPrice" name="price" value="@price" type="number" min="0" step="0.01" required />
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-field">
|
|
<label class="form-field__label" for="transactionItemQuantity">
|
|
Quantity @if (unit != null) { <text>(@unit)</text> }
|
|
</label>
|
|
<div class="form-field__control input">
|
|
@{ var step = unit == null ? "1" : "0.001"; }
|
|
<input class="input__control" id="transactionItemQuantity" name="quantity" value="@(unit == null ? (int?)quantity : quantity)" type="number" min="@step" step="@step" required />
|
|
</div>
|
|
</div>
|
|
|
|
<input type="hidden" name="unit" value="@unit" />
|
|
</div>
|
|
|
|
@ChildContent
|
|
</form>
|
|
|
|
@code {
|
|
[Parameter, EditorRequired]
|
|
public required TransactionItem TransactionItem { get; set; }
|
|
|
|
[Parameter]
|
|
public RenderFragment? ChildContent { get; set; }
|
|
|
|
[Parameter(CaptureUnmatchedValues = true)]
|
|
public Dictionary<string, object>? AdditionalAttributes { get; set; }
|
|
|
|
private record ItemModel(Guid Id, string Brand, string Name, decimal? Price, decimal? Quantity);
|
|
|
|
private ItemBarcode? barcode;
|
|
|
|
private ItemModel[] items = [];
|
|
private ItemModel? selectedItem;
|
|
|
|
private decimal? price;
|
|
private decimal? quantity;
|
|
private string? unit;
|
|
|
|
protected override async Task OnParametersSetAsync()
|
|
{
|
|
barcode = TransactionItem.Item?.Barcodes.FirstOrDefault();
|
|
|
|
using var dbContext = DbContextFactory.CreateDbContext();
|
|
items = await dbContext.Items
|
|
.OrderBy(item => item.Brand)
|
|
.ThenBy(item => item.Name)
|
|
.LeftJoin(
|
|
dbContext.ItemPurchases.Where(purchase => purchase.IsLastPurchase),
|
|
item => item.Id,
|
|
lastPurchase => lastPurchase.ItemId,
|
|
(item, lastPurchase) => new ItemModel(
|
|
item.Id,
|
|
item.Brand,
|
|
item.Name,
|
|
lastPurchase != null ? lastPurchase.Price : null,
|
|
lastPurchase != null ? lastPurchase.Quantity : null))
|
|
.ToArrayAsync();
|
|
|
|
selectedItem = items.SingleOrDefault(item => item.Id == TransactionItem.ItemId);
|
|
|
|
price = TransactionItem.Price >= 0 ? TransactionItem.Price : selectedItem?.Price;
|
|
quantity = TransactionItem.Quantity >= 0 ? TransactionItem.Quantity : selectedItem?.Quantity;
|
|
unit = TransactionItem.Unit;
|
|
|
|
if (unit == null)
|
|
{
|
|
quantity ??= 1;
|
|
}
|
|
}
|
|
}
|