Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 36 additions & 11 deletions CulinaryCommandApp/Components/Layout/NavMenu.razor
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
@using CulinaryCommand.Components.Custom
@using CulinaryCommand.Services
@inject IUserContextService UserCtx
@inject LocationState LocationState
@inject NavigationManager Nav
@implements IDisposable
@rendermode InteractiveServer

<div class="top-row ps-3 navbar navbar-dark">
Expand Down Expand Up @@ -36,9 +39,10 @@
</div>

<div class="nav-item px-3">
<NavLink class="nav-link" href="/inventory-management">
<a class="nav-link @(Nav.Uri.Contains("/inventory-management") ? "active" : "")"
href="#" @onclick="async () => await GoToInventory()" @onclick:preventDefault="true">
<span class="bi bi-box-seam nav-icon" aria-hidden="true"></span> Inventory
</NavLink>
</a>
</div>

@if (_role == "Admin")
Expand Down Expand Up @@ -81,12 +85,6 @@
<span class="bi bi-basket3 nav-icon"></span> Ingredients
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="/inventory-management">
<span class="bi bi-box-seam nav-icon"></span> Inventory
</NavLink>
</div>

<div class="nav-item px-3">
<NavLink class="nav-link" href="/inventory-catalog">
<span class="bi bi-card-list nav-icon" aria-hidden="true"></span> Inventory Catalog
Expand All @@ -109,9 +107,36 @@

protected override async Task OnInitializedAsync()
{
// Compile-safe even if auth isn't working yet:
// - If not authenticated or DB user not found, _role stays null.
var ctx = await UserCtx.GetAsync();
_role = ctx.User?.Role;

LocationState.OnChange += HandleLocationChange;
}

private async Task GoToInventory()
{
var locId = LocationState.CurrentLocation?.Id;

if (!locId.HasValue)
{
var ctx = await UserCtx.GetAsync();
locId = ctx.AccessibleLocations.FirstOrDefault()?.Id;
}

var href = locId.HasValue
? $"/inventory-management/{locId.Value}"
: "/inventory-management";

Comment on lines +126 to +129
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GoToInventory() can navigate to /inventory-management when no location is resolved, but the Inventory page route is now /inventory-management/{LocationId:int}. This fallback will 404. Either add a non-parameter route that redirects/chooses a location, or ensure navigation always supplies a valid LocationId.

Suggested change
var href = locId.HasValue
? $"/inventory-management/{locId.Value}"
: "/inventory-management";
if (!locId.HasValue)
{
// No resolvable location; do not navigate to avoid hitting a 404 route.
return;
}
var href = $"/inventory-management/{locId.Value}";

Copilot uses AI. Check for mistakes.
Nav.NavigateTo(href);
}

private void HandleLocationChange()
{
InvokeAsync(StateHasChanged);
}

public void Dispose()
{
LocationState.OnChange -= HandleLocationChange;
}
}
}
15 changes: 15 additions & 0 deletions CulinaryCommandApp/Data/AppDbContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,21 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
.WithMany(l => l.ManagerLocations)
.HasForeignKey(ml => ml.LocationId);

// Ingredient belongs to a Location
modelBuilder.Entity<CulinaryCommand.Inventory.Entities.Ingredient>()
.HasOne(i => i.Location)
.WithMany()
.HasForeignKey(i => i.LocationId)
.OnDelete(DeleteBehavior.Cascade);

// Ingredient optionally belongs to a Vendor
modelBuilder.Entity<CulinaryCommand.Inventory.Entities.Ingredient>()
.HasOne(i => i.Vendor)
.WithMany()
.HasForeignKey(i => i.VendorId)
.OnDelete(DeleteBehavior.SetNull)
.IsRequired(false);

// Vendor belongs to a Company
modelBuilder.Entity<V.Vendor>()
.HasOne(v => v.Company)
Expand Down
5 changes: 3 additions & 2 deletions CulinaryCommandApp/Inventory/DTOs/CreateIngredientDTO.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@ public class CreateIngredientDTO
public decimal CurrentQuantity { get; set; } = 0;
public decimal Price { get; set; } = 0m;
public string? Category { get; set; }
// used to determine if restock is needed
public decimal ReorderLevel { get; set; } = 0m;
// Use an integer Id to reference the Unit (ex: a foreign key to the Units table)
[Range(1, int.MaxValue, ErrorMessage = "UnitId must be a positive integer.")]
public int UnitId { get; set; }
[Range(1, int.MaxValue, ErrorMessage = "LocationId must be a positive integer.")]
public int LocationId { get; set; }
public int? VendorId { get; set; }
}
}
3 changes: 3 additions & 0 deletions CulinaryCommandApp/Inventory/DTOs/InventoryItemDTO.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,8 @@ public class InventoryItemDTO
public DateTime? OutOfStockDate { get; set; }
public DateTime? LastOrderDate { get; set; }
public string? Notes { get; set; }
public int? VendorId { get; set; }
public string? VendorName { get; set; }
public string? VendorLogoUrl { get; set; }
}
}
10 changes: 9 additions & 1 deletion CulinaryCommandApp/Inventory/Entities/Ingredient.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using CulinaryCommand.Data.Entities;

namespace CulinaryCommand.Inventory.Entities
{
Expand All @@ -9,6 +10,14 @@ public class Ingredient
// display name of the ingredient (ex: "flour", "eggs")
public string Name { get; set; } = string.Empty;

// fk to the location this ingredient belongs to
public int LocationId { get; set; }
public Location? Location { get; set; }

// optional fk to the vendor that supplies this ingredient
public int? VendorId { get; set; }
public CulinaryCommand.Vendor.Entities.Vendor? Vendor { get; set; }

// fk to the unit used to track stock (ex: g, kg, each).
public int UnitId { get; set; }

Expand Down Expand Up @@ -39,5 +48,4 @@ public class Ingredient
// optional, used to describe any details about the ingredient
public string? Notes { get; set; }
}

}
Loading
Loading