diff --git a/CulinaryCommandApp/Components/Layout/NavMenu.razor b/CulinaryCommandApp/Components/Layout/NavMenu.razor
index 3d64bda..7cc76f7 100644
--- a/CulinaryCommandApp/Components/Layout/NavMenu.razor
+++ b/CulinaryCommandApp/Components/Layout/NavMenu.razor
@@ -5,6 +5,9 @@
@using CulinaryCommand.Components.Custom
@using CulinaryCommand.Services
@inject IUserContextService UserCtx
+@inject LocationState LocationState
+@inject NavigationManager Nav
+@implements IDisposable
@rendermode InteractiveServer
@@ -36,9 +39,10 @@
@if (_role == "Admin")
@@ -81,12 +85,6 @@
Ingredients
-
-
- Inventory
-
-
-
Inventory Catalog
@@ -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";
+
+ Nav.NavigateTo(href);
+ }
+
+ private void HandleLocationChange()
+ {
+ InvokeAsync(StateHasChanged);
+ }
+
+ public void Dispose()
+ {
+ LocationState.OnChange -= HandleLocationChange;
}
-}
+}
\ No newline at end of file
diff --git a/CulinaryCommandApp/Data/AppDbContext.cs b/CulinaryCommandApp/Data/AppDbContext.cs
index 4aa058f..c37eb03 100644
--- a/CulinaryCommandApp/Data/AppDbContext.cs
+++ b/CulinaryCommandApp/Data/AppDbContext.cs
@@ -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()
+ .HasOne(i => i.Location)
+ .WithMany()
+ .HasForeignKey(i => i.LocationId)
+ .OnDelete(DeleteBehavior.Cascade);
+
+ // Ingredient optionally belongs to a Vendor
+ modelBuilder.Entity()
+ .HasOne(i => i.Vendor)
+ .WithMany()
+ .HasForeignKey(i => i.VendorId)
+ .OnDelete(DeleteBehavior.SetNull)
+ .IsRequired(false);
+
// Vendor belongs to a Company
modelBuilder.Entity()
.HasOne(v => v.Company)
diff --git a/CulinaryCommandApp/Inventory/DTOs/CreateIngredientDTO.cs b/CulinaryCommandApp/Inventory/DTOs/CreateIngredientDTO.cs
index 0724c6e..84abe90 100644
--- a/CulinaryCommandApp/Inventory/DTOs/CreateIngredientDTO.cs
+++ b/CulinaryCommandApp/Inventory/DTOs/CreateIngredientDTO.cs
@@ -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; }
}
}
\ No newline at end of file
diff --git a/CulinaryCommandApp/Inventory/DTOs/InventoryItemDTO.cs b/CulinaryCommandApp/Inventory/DTOs/InventoryItemDTO.cs
index 082b78c..0304346 100644
--- a/CulinaryCommandApp/Inventory/DTOs/InventoryItemDTO.cs
+++ b/CulinaryCommandApp/Inventory/DTOs/InventoryItemDTO.cs
@@ -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; }
}
}
diff --git a/CulinaryCommandApp/Inventory/Entities/Ingredient.cs b/CulinaryCommandApp/Inventory/Entities/Ingredient.cs
index c7c1944..11df568 100644
--- a/CulinaryCommandApp/Inventory/Entities/Ingredient.cs
+++ b/CulinaryCommandApp/Inventory/Entities/Ingredient.cs
@@ -1,4 +1,5 @@
using System;
+using CulinaryCommand.Data.Entities;
namespace CulinaryCommand.Inventory.Entities
{
@@ -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; }
@@ -39,5 +48,4 @@ public class Ingredient
// optional, used to describe any details about the ingredient
public string? Notes { get; set; }
}
-
}
\ No newline at end of file
diff --git a/CulinaryCommandApp/Inventory/Pages/Inventory/InventoryManagement.razor b/CulinaryCommandApp/Inventory/Pages/Inventory/InventoryManagement.razor
index a99416a..e24b7c3 100644
--- a/CulinaryCommandApp/Inventory/Pages/Inventory/InventoryManagement.razor
+++ b/CulinaryCommandApp/Inventory/Pages/Inventory/InventoryManagement.razor
@@ -1,10 +1,23 @@
-@page "/inventory-management"
+@page "/inventory-management/{LocationId:int}"
@rendermode InteractiveServer
+@implements IDisposable
@using CulinaryCommand.Inventory.DTOs
+@using CulinaryCommand.Inventory.Entities
+@using CulinaryCommand.Inventory.Services
+@using CulinaryCommand.Inventory.Services.Interfaces
@using Microsoft.JSInterop
@using Microsoft.AspNetCore.Components.Forms
-@using System.Threading.Tasks
+
+@using CulinaryCommand.Vendor.Services
+@using CulinaryCommand.Vendor.Entities
+@using CulinaryCommand.Services
+
+@inject IInventoryManagementService InventoryService
+@inject IUnitService UnitService
+@inject IVendorService VendorService
+@inject LocationState LocationState
+@inject NavigationManager Nav