@page "/projects/new" @page "/projects/{Id:int}" @inject ProjectService ProjectService @inject MaterialService MaterialService @inject SupplierService SupplierService @inject NavigationManager Navigation @using CutList.Core.Formatting @(IsNew ? "New Project" : project.Name)

@(IsNew ? "New Project" : project.Name)

@if (!IsNew) { Run Optimization }
@if (loading) {

Loading...

} else {
Project Details
@foreach (var material in materials) { }
@foreach (var tool in cuttingTools) { }
@if (!string.IsNullOrEmpty(projectErrorMessage)) {
@projectErrorMessage
}
Back
@if (!IsNew) {
Parts
@if (showPartForm) {
@if (!string.IsNullOrEmpty(partErrorMessage)) {
@partErrorMessage
}
} @if (project.Parts.Count == 0) {

No parts added yet.

} else { @foreach (var part in project.Parts) { }
Name Length Qty
@part.Name @ArchUnits.FormatFromInches((double)part.LengthInches) @part.Quantity
Total: @project.Parts.Sum(p => p.Quantity) pieces
}
Stock Bins
@if (showImportDialog) {
Import from Supplier
} @if (showBinForm) {
-1 = unlimited
@if (!string.IsNullOrEmpty(binErrorMessage)) {
@binErrorMessage
}
} @if (project.StockBins.Count == 0) {

No stock bins added yet.

} else { @foreach (var bin in project.StockBins.OrderBy(b => b.Priority).ThenBy(b => b.LengthInches)) { }
Length Qty Priority
@ArchUnits.FormatFromInches((double)bin.LengthInches) @(bin.Quantity == -1 ? "Unlimited" : bin.Quantity.ToString()) @bin.Priority
}
}
} @code { [Parameter] public int? Id { get; set; } private Project project = new(); private List materials = new(); private List cuttingTools = new(); private List suppliers = new(); private bool loading = true; private bool savingProject; private string? projectErrorMessage; // Parts form private bool showPartForm; private ProjectPart newPart = new(); private ProjectPart? editingPart; private string? partErrorMessage; // Bins form private bool showBinForm; private ProjectStockBin newBin = new(); private ProjectStockBin? editingBin; private string? binErrorMessage; // Import dialog private bool showImportDialog; private int selectedSupplierId; private bool IsNew => !Id.HasValue; protected override async Task OnInitializedAsync() { materials = await MaterialService.GetAllAsync(); cuttingTools = await ProjectService.GetCuttingToolsAsync(); suppliers = await SupplierService.GetAllAsync(); if (Id.HasValue) { var existing = await ProjectService.GetByIdAsync(Id.Value); if (existing == null) { Navigation.NavigateTo("projects"); return; } project = existing; } else { // Set default cutting tool for new projects var defaultTool = await ProjectService.GetDefaultCuttingToolAsync(); if (defaultTool != null) { project.CuttingToolId = defaultTool.Id; } } loading = false; } private async Task SaveProjectAsync() { projectErrorMessage = null; savingProject = true; try { if (string.IsNullOrWhiteSpace(project.Name)) { projectErrorMessage = "Project name is required"; return; } if (IsNew) { var created = await ProjectService.CreateAsync(project); Navigation.NavigateTo($"projects/{created.Id}"); } else { await ProjectService.UpdateAsync(project); } } finally { savingProject = false; } } // Parts methods private void ShowAddPartForm() { editingPart = null; newPart = new ProjectPart { ProjectId = Id!.Value, Quantity = 1 }; showPartForm = true; partErrorMessage = null; } private void EditPart(ProjectPart part) { editingPart = part; newPart = new ProjectPart { Id = part.Id, ProjectId = part.ProjectId, Name = part.Name, LengthInches = part.LengthInches, Quantity = part.Quantity, SortOrder = part.SortOrder }; showPartForm = true; partErrorMessage = null; } private void CancelPartForm() { showPartForm = false; editingPart = null; } private async Task SavePartAsync() { partErrorMessage = null; if (string.IsNullOrWhiteSpace(newPart.Name)) { partErrorMessage = "Name is required"; return; } if (newPart.LengthInches <= 0) { partErrorMessage = "Length must be greater than zero"; return; } if (newPart.Quantity < 1) { partErrorMessage = "Quantity must be at least 1"; return; } if (editingPart == null) { await ProjectService.AddPartAsync(newPart); } else { await ProjectService.UpdatePartAsync(newPart); } project = (await ProjectService.GetByIdAsync(Id!.Value))!; showPartForm = false; editingPart = null; } private async Task DeletePart(ProjectPart part) { await ProjectService.DeletePartAsync(part.Id); project = (await ProjectService.GetByIdAsync(Id!.Value))!; } // Bins methods private void ShowAddBinForm() { editingBin = null; newBin = new ProjectStockBin { ProjectId = Id!.Value, Quantity = -1, Priority = 25 }; showBinForm = true; binErrorMessage = null; } private void EditBin(ProjectStockBin bin) { editingBin = bin; newBin = new ProjectStockBin { Id = bin.Id, ProjectId = bin.ProjectId, LengthInches = bin.LengthInches, Quantity = bin.Quantity, Priority = bin.Priority, SortOrder = bin.SortOrder }; showBinForm = true; binErrorMessage = null; } private void CancelBinForm() { showBinForm = false; editingBin = null; } private async Task SaveBinAsync() { binErrorMessage = null; if (newBin.LengthInches <= 0) { binErrorMessage = "Length must be greater than zero"; return; } if (newBin.Quantity < -1 || newBin.Quantity == 0) { binErrorMessage = "Quantity must be positive or -1 for unlimited"; return; } if (editingBin == null) { await ProjectService.AddStockBinAsync(newBin); } else { await ProjectService.UpdateStockBinAsync(newBin); } project = (await ProjectService.GetByIdAsync(Id!.Value))!; showBinForm = false; editingBin = null; } private async Task DeleteBin(ProjectStockBin bin) { await ProjectService.DeleteStockBinAsync(bin.Id); project = (await ProjectService.GetByIdAsync(Id!.Value))!; } // Import methods private void ShowImportDialog() { selectedSupplierId = 0; showImportDialog = true; } private async Task ImportFromSupplier() { if (selectedSupplierId > 0) { await ProjectService.ImportStockFromSupplierAsync(Id!.Value, selectedSupplierId, project.MaterialId); project = (await ProjectService.GetByIdAsync(Id!.Value))!; showImportDialog = false; } } }