@page "/materials" @inject MaterialService MaterialService @inject NavigationManager Navigation Materials

Materials

Add Material

Manage your material catalog here. Materials define the types of stock you work with — shape, size, type, and grade. Once added, materials can be assigned to jobs and used to generate optimized cut lists.

@if (loading) {

Loading...

} else if (!string.IsNullOrEmpty(errorMessage)) {
Error loading materials:
@errorMessage
} else if (materials.Count == 0) {
No materials found. Add your first material.
} else { @if (filteredMaterials.Count == 0) {
No materials match your filters.
} else { @foreach (var material in pagedMaterials) { }
Shape Type Grade Size Actions
@material.Shape.GetDisplayName() @material.Type @material.Grade @material.Size
} } @code { private List materials = new(); private bool loading = true; private string? errorMessage; private int currentPage = 1; private int pageSize = 25; private ConfirmDialog deleteDialog = null!; private Material? materialToDelete; private string deleteMessage = ""; private MaterialFilterState filterState = new(); private List filteredMaterials => materials.Where(m => { 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)) return false; } return true; }).ToList(); private IEnumerable availableGrades => materials .Select(m => m.Grade) .Where(g => !string.IsNullOrEmpty(g)) .Distinct() .OrderBy(g => g)!; private IEnumerable pagedMaterials => filteredMaterials .Skip((currentPage - 1) * pageSize) .Take(pageSize); protected override async Task OnInitializedAsync() { try { materials = await MaterialService.GetAllAsync(); } catch (Exception ex) { errorMessage = ex.ToString(); } finally { loading = false; } } private void OnFilterChanged(MaterialFilterState state) { filterState = state; currentPage = 1; } private void ConfirmDelete(Material material) { materialToDelete = material; deleteMessage = $"Are you sure you want to delete \"{material.Shape} - {material.Size}\"?"; deleteDialog.Show(); } private async Task DeleteConfirmed() { if (materialToDelete != null) { await MaterialService.DeleteAsync(materialToDelete.Id); materials = await MaterialService.GetAllAsync(); var totalPages = (int)Math.Ceiling((double)filteredMaterials.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); }