@page "/stock" @inject StockItemService StockItemService @inject NavigationManager Navigation @using CutList.Core.Formatting @using CutList.Web.Data.Entities Stock Items

Stock Items

Add Stock Item

Stock items represent the specific lengths of material you have available for cutting. Each stock item links a material to a length and tracks how many pieces you have on hand.

@if (loading) {

Loading...

} else if (stockItems.Count == 0) {
No stock items found. Add your first stock item.
} else { @if (filteredItems.Count == 0) {
No stock items match your filters.
} else { @foreach (var item in pagedItems) { }
Shape Type Grade Size Length On Hand Actions
@item.Material.Shape.GetDisplayName() @item.Material.Type @item.Material.Grade @item.Material.Size @ArchUnits.FormatFromInches((double)item.LengthInches) @if (item.QuantityOnHand > 0) { @item.QuantityOnHand } else { 0 }
} } @code { private List stockItems = new(); private bool loading = true; private int currentPage = 1; private int pageSize = 25; private ConfirmDialog deleteDialog = null!; private StockItem? itemToDelete; private string deleteMessage = ""; private MaterialFilterState filterState = new(); private List filteredItems => stockItems.Where(s => { var m = s.Material; if (filterState.Shape.HasValue && m.Shape != filterState.Shape.Value) return false; if (filterState.Type.HasValue && m.Type != filterState.Type.Value) return false; if (!string.IsNullOrEmpty(filterState.Grade) && m.Grade != filterState.Grade) return false; if (!string.IsNullOrWhiteSpace(filterState.SearchText)) { var search = filterState.SearchText.Trim(); if (!Contains(m.Size, search) && !Contains(m.Grade, search) && !Contains(m.Description, search) && !Contains(m.Shape.GetDisplayName(), search) && !Contains(s.Name, search) && !Contains(s.Notes, search)) return false; } return true; }).ToList(); private IEnumerable availableGrades => stockItems .Select(s => s.Material.Grade) .Where(g => !string.IsNullOrEmpty(g)) .Distinct() .OrderBy(g => g)!; private IEnumerable pagedItems => filteredItems .Skip((currentPage - 1) * pageSize) .Take(pageSize); protected override async Task OnInitializedAsync() { stockItems = await StockItemService.GetAllAsync(); loading = false; } private void OnFilterChanged(MaterialFilterState state) { filterState = state; currentPage = 1; } private void ConfirmDelete(StockItem item) { itemToDelete = item; deleteMessage = $"Are you sure you want to delete \"{item.Material.DisplayName} - {ArchUnits.FormatFromInches((double)item.LengthInches)}\"?"; deleteDialog.Show(); } private async Task DeleteConfirmed() { if (itemToDelete != null) { await StockItemService.DeleteAsync(itemToDelete.Id); stockItems = await StockItemService.GetAllAsync(); var totalPages = (int)Math.Ceiling((double)filteredItems.Count / pageSize); if (currentPage > totalPages && totalPages > 0) currentPage = totalPages; } } private void OnPageChanged(int page) => currentPage = page; private static bool Contains(string? value, string search) => value != null && value.Contains(search, StringComparison.OrdinalIgnoreCase); }