From af3413906770a3d83e185cc9eca92e34e6bf47dd Mon Sep 17 00:00:00 2001 From: Mikayla Dobson Date: Mon, 4 Dec 2023 16:04:01 -0600 Subject: [PATCH] support for displaying ingredient metadata --- .gitignore | 1 + Unbinder.sln | 8 +- Unbinder/Controllers/RecipeController.cs | 23 ++-- Unbinder/DB/Initializer.cs | 33 ++++-- Unbinder/DB/SQL/truncate_database.sql | 3 + Unbinder/DB/SeedData.cs | 108 ++++++++++++++++++ ...0231117145840_InitialMigration.Designer.cs | 2 +- ...17150919_RemoveIngredientArray.Designer.cs | 2 +- ...31201185549_update-table-names.Designer.cs | 2 +- ...72304_RecipeIngredientRelation.Designer.cs | 2 +- ...20231204213851_ModifyDataTypes.Designer.cs | 108 ++++++++++++++++++ .../20231204213851_ModifyDataTypes.cs | 36 ++++++ .../UnbinderDbContextModelSnapshot.cs | 7 +- Unbinder/Models/IngredientWithDetails.cs | 15 +++ Unbinder/Models/RecipeIngredient.cs | 2 +- Unbinder/Program.cs | 1 + .../IRecipeIngredientRepository.cs | 1 + .../RecipeIngredientRepository.cs | 48 +++++++- Unbinder/Unbinder.csproj | 1 - Unbinder/ViewModels/RecipeViewModel.cs | 10 ++ Unbinder/Views/Recipe/RecipeId.cshtml | 41 ++++++- 21 files changed, 416 insertions(+), 38 deletions(-) create mode 100644 Unbinder/DB/SQL/truncate_database.sql create mode 100644 Unbinder/Migrations/20231204213851_ModifyDataTypes.Designer.cs create mode 100644 Unbinder/Migrations/20231204213851_ModifyDataTypes.cs create mode 100644 Unbinder/Models/IngredientWithDetails.cs create mode 100644 Unbinder/ViewModels/RecipeViewModel.cs diff --git a/.gitignore b/.gitignore index 72610cf..4505dc2 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ # GITIGNORE FILES ADDED BY MIKAYLA __notes__ *.env +UnbinderSandbox # Files for/generated by Docker Compose secrets diff --git a/Unbinder.sln b/Unbinder.sln index 2078554..63b03e8 100644 --- a/Unbinder.sln +++ b/Unbinder.sln @@ -3,7 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.7.34031.279 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Unbinder", "Unbinder\Unbinder.csproj", "{620A53DB-415A-4741-ABDE-5E2B78197CF7}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Unbinder", "Unbinder\Unbinder.csproj", "{620A53DB-415A-4741-ABDE-5E2B78197CF7}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnbinderSandbox", "UnbinderSandbox\UnbinderSandbox.csproj", "{A75CD739-80D1-4D96-A828-52B3F49B8254}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -15,6 +17,10 @@ Global {620A53DB-415A-4741-ABDE-5E2B78197CF7}.Debug|Any CPU.Build.0 = Debug|Any CPU {620A53DB-415A-4741-ABDE-5E2B78197CF7}.Release|Any CPU.ActiveCfg = Release|Any CPU {620A53DB-415A-4741-ABDE-5E2B78197CF7}.Release|Any CPU.Build.0 = Release|Any CPU + {A75CD739-80D1-4D96-A828-52B3F49B8254}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A75CD739-80D1-4D96-A828-52B3F49B8254}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A75CD739-80D1-4D96-A828-52B3F49B8254}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A75CD739-80D1-4D96-A828-52B3F49B8254}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Unbinder/Controllers/RecipeController.cs b/Unbinder/Controllers/RecipeController.cs index 7631a40..341a5bd 100644 --- a/Unbinder/Controllers/RecipeController.cs +++ b/Unbinder/Controllers/RecipeController.cs @@ -1,12 +1,14 @@ using Microsoft.AspNetCore.Mvc; using Unbinder.Models; using Unbinder.Repositories; +using Unbinder.ViewModels; namespace Unbinder.Controllers { - public class RecipeController(IRecipeRepository recipeRepository) : Controller + public class RecipeController(IRecipeRepository recipeRepository, IRecipeIngredientRepository recipeIngredientRepository) : Controller { private readonly IRecipeRepository _recipeRepository = recipeRepository; + private readonly IRecipeIngredientRepository _recipeIngredientRepository = recipeIngredientRepository; public IActionResult Index() { @@ -16,18 +18,19 @@ namespace Unbinder.Controllers : View(result); } - [Route("[controller]/{id}")] - public IActionResult RecipeId(int id, bool editMode = false) + [Route("[controller]/{recipeId}")] + public IActionResult RecipeId(int recipeId, bool editMode = false) { - var result = _recipeRepository.GetById(id); - - Console.WriteLine(result == null ? "No result found" : result); - ViewBag.EditMode = editMode; - return result == null - ? NotFound() - : View(result); + var recipe = _recipeRepository.GetById(recipeId); + if (recipe == null) return NotFound(); + var ingredients = _recipeIngredientRepository.GetIngredientsByRecipeId(recipeId); + + + + RecipeViewModel recipeViewModel = new(recipe, ingredients); + return View(recipeViewModel); } [Route("[controller]/search")] diff --git a/Unbinder/DB/Initializer.cs b/Unbinder/DB/Initializer.cs index 2f703e9..fec9399 100644 --- a/Unbinder/DB/Initializer.cs +++ b/Unbinder/DB/Initializer.cs @@ -1,10 +1,13 @@ -using Unbinder.Models; +using Microsoft.Extensions.Logging; +using Unbinder.Models; using Unbinder.Repositories; namespace Unbinder.DB { public static class Initializer { + private static readonly ILogger logger = new LoggerFactory().CreateLogger("DBInitializer"); + public static int Seed(IApplicationBuilder applicationBuilder) { int totalInsertCount = 0; @@ -12,7 +15,7 @@ namespace Unbinder.DB using UnbinderDbContext context = applicationBuilder.ApplicationServices.CreateScope() .ServiceProvider.GetRequiredService(); - Console.WriteLine("Connection established, preparing to seed database..."); + logger.Log(LogLevel.Information, "Connection established, preparing to seed database..."); // if records are not already seeded, do an initial insert into DB WriteIfNotInitialized(context.Recipes, SeedData.InitialRecipes, context.Recipes.AddRange); @@ -20,7 +23,7 @@ namespace Unbinder.DB // save changes so we can references them for establishing relations int insertCount = context.SaveChanges(); - Console.WriteLine($"Seeded {insertCount} records"); + logger.Log(LogLevel.Information, $"Seeded {insertCount} records"); totalInsertCount += insertCount; // establish relations if they do not already exist @@ -29,16 +32,14 @@ namespace Unbinder.DB if (padThai != null) { - Console.WriteLine("Found Pad Thai recipe, checking relations..."); - var padThaiIngredientNames = SeedData.PadThaiIngredients.Select(i => i.Name); - AddRelations(context, padThaiIngredientNames, padThai.RecipeId); + logger.Log(LogLevel.Information, "Found Pad Thai recipe, checking relations..."); + AddRelations(context, SeedData.PadThaiIngredientsWithDetails, padThai.RecipeId); } if (pancakes != null) { - Console.WriteLine("Found Pancakes recipe, checking relations..."); - var pancakeIngredientNames = SeedData.PancakeIngredients.Select(i => i.Name); - AddRelations(context, pancakeIngredientNames, pancakes.RecipeId); + logger.Log(LogLevel.Information, "Found Pancakes recipe, checking relations..."); + AddRelations(context, SeedData.PancakeIngredientsWithDetails, pancakes.RecipeId); } totalInsertCount += context.SaveChanges(); @@ -50,23 +51,31 @@ namespace Unbinder.DB private static void WriteIfNotInitialized(IEnumerable existingItems, IEnumerable seedData, Callback addRange) { if (existingItems.Any()) { - Console.WriteLine("Record already exists in the database"); + logger.Log(LogLevel.Information, "Record already exists in the database"); return; } addRange(seedData); } - private static void AddRelations(UnbinderDbContext context, IEnumerable names, int id) + private static void AddRelations(UnbinderDbContext context, IngredientWithDetails[] details, int recipeId) { + var names = details.Select(d => d.Ingredient.Name); + foreach (var ing in context.Ingredients) { if (names.Contains(ing.Name)) { + logger.Log(LogLevel.Information, $"Writing entry for {ing.Name}"); + + var entryForThis = details.Where(d => d.Ingredient.Name == ing.Name).FirstOrDefault(); + context.RecipeIngredients.Add(new RecipeIngredient { - RecipeId = id, + RecipeId = recipeId, IngredientId = ing.IngredientId, + Amount = entryForThis?.Details.Amount, + Unit = entryForThis?.Details.Unit, }); } } diff --git a/Unbinder/DB/SQL/truncate_database.sql b/Unbinder/DB/SQL/truncate_database.sql new file mode 100644 index 0000000..61c9448 --- /dev/null +++ b/Unbinder/DB/SQL/truncate_database.sql @@ -0,0 +1,3 @@ +TRUNCATE TABLE Ingredients; +TRUNCATE TABLE RecipeIngredients; +TRUNCATE TABLE Recipes; diff --git a/Unbinder/DB/SeedData.cs b/Unbinder/DB/SeedData.cs index df6a23a..2f10c83 100644 --- a/Unbinder/DB/SeedData.cs +++ b/Unbinder/DB/SeedData.cs @@ -37,6 +37,69 @@ namespace Unbinder.DB public static Recipe[] InitialRecipes => [PadThaiRecipe, PancakeRecipe]; + public static IngredientWithDetails[] PadThaiIngredientsWithDetails + { + get + { + return [ + new IngredientWithDetails + { + Ingredient = PadThaiIngredients[0], + Details = new IngredientDetails + { + Amount = 1, + Unit = "Bunch, roughly chopped" + } + }, + new IngredientWithDetails + { + Ingredient = PadThaiIngredients[1], + Details = new IngredientDetails + { + Amount = 1, + Unit = "Lime (juice)" + } + }, + new IngredientWithDetails + { + Ingredient = PadThaiIngredients[2], + Details = new IngredientDetails + { + Amount = 0.25, + Unit = "Cup (chopped)", + } + }, + new IngredientWithDetails + { + Ingredient = PadThaiIngredients[3], + Details = new IngredientDetails + { + Amount = 16, + Unit = "oz." + } + }, + new IngredientWithDetails + { + Ingredient = PadThaiIngredients[4], + Details = new IngredientDetails + { + Amount = 1, + Unit = "Egg (scrambled)" + } + }, + new IngredientWithDetails + { + Ingredient = PadThaiIngredients[5], + Details = new IngredientDetails + { + Amount = 1, + Unit = "Block (diced)" + } + } + ]; + } + } + public static Ingredient[] PadThaiIngredients { get @@ -104,6 +167,51 @@ namespace Unbinder.DB } } + public static IngredientWithDetails[] PancakeIngredientsWithDetails + { + get + { + return [ + new IngredientWithDetails + { + Ingredient = PancakeIngredients[0], + Details = new IngredientDetails + { + Amount = 2, + Unit = "cups", + } + }, + new IngredientWithDetails + { + Ingredient = PancakeIngredients[1], + Details = new IngredientDetails + { + Amount = 1, + Unit = "teaspoon" + } + }, + new IngredientWithDetails + { + Ingredient = PancakeIngredients[2], + Details = new IngredientDetails + { + Amount = 1, + Unit = "teaspoon", + } + }, + new IngredientWithDetails + { + Ingredient = PancakeIngredients[3], + Details = new IngredientDetails + { + Amount = 2, + Unit = "tablespoons" + } + } + ]; + } + } + public static Ingredient[] InitialIngredients => PadThaiIngredients.Concat(PancakeIngredients).ToArray(); } } diff --git a/Unbinder/Migrations/20231117145840_InitialMigration.Designer.cs b/Unbinder/Migrations/20231117145840_InitialMigration.Designer.cs index d779e2a..5a12d9c 100644 --- a/Unbinder/Migrations/20231117145840_InitialMigration.Designer.cs +++ b/Unbinder/Migrations/20231117145840_InitialMigration.Designer.cs @@ -11,7 +11,7 @@ using Unbinder.DB; namespace Unbinder.Migrations { - [DbContext(typeof(UnbinderDbContext))] + [DbContext(typeof(Initializer))] [Migration("20231117145840_InitialMigration")] partial class InitialMigration { diff --git a/Unbinder/Migrations/20231117150919_RemoveIngredientArray.Designer.cs b/Unbinder/Migrations/20231117150919_RemoveIngredientArray.Designer.cs index 5d76a13..ccfcef6 100644 --- a/Unbinder/Migrations/20231117150919_RemoveIngredientArray.Designer.cs +++ b/Unbinder/Migrations/20231117150919_RemoveIngredientArray.Designer.cs @@ -10,7 +10,7 @@ using Unbinder.DB; namespace Unbinder.Migrations { - [DbContext(typeof(UnbinderDbContext))] + [DbContext(typeof(Initializer))] [Migration("20231117150919_RemoveIngredientArray")] partial class RemoveIngredientArray { diff --git a/Unbinder/Migrations/20231201185549_update-table-names.Designer.cs b/Unbinder/Migrations/20231201185549_update-table-names.Designer.cs index 63f7b3d..bbef403 100644 --- a/Unbinder/Migrations/20231201185549_update-table-names.Designer.cs +++ b/Unbinder/Migrations/20231201185549_update-table-names.Designer.cs @@ -10,7 +10,7 @@ using Unbinder.DB; namespace Unbinder.Migrations { - [DbContext(typeof(UnbinderDbContext))] + [DbContext(typeof(Initializer))] [Migration("20231201185549_update-table-names")] partial class updatetablenames { diff --git a/Unbinder/Migrations/20231204172304_RecipeIngredientRelation.Designer.cs b/Unbinder/Migrations/20231204172304_RecipeIngredientRelation.Designer.cs index 6f557a5..ccea4ed 100644 --- a/Unbinder/Migrations/20231204172304_RecipeIngredientRelation.Designer.cs +++ b/Unbinder/Migrations/20231204172304_RecipeIngredientRelation.Designer.cs @@ -10,7 +10,7 @@ using Unbinder.DB; namespace Unbinder.Migrations { - [DbContext(typeof(UnbinderDbContext))] + [DbContext(typeof(Initializer))] [Migration("20231204172304_RecipeIngredientRelation")] partial class RecipeIngredientRelation { diff --git a/Unbinder/Migrations/20231204213851_ModifyDataTypes.Designer.cs b/Unbinder/Migrations/20231204213851_ModifyDataTypes.Designer.cs new file mode 100644 index 0000000..d64edd7 --- /dev/null +++ b/Unbinder/Migrations/20231204213851_ModifyDataTypes.Designer.cs @@ -0,0 +1,108 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Unbinder.DB; + +#nullable disable + +namespace Unbinder.Migrations +{ + [DbContext(typeof(Initializer))] + [Migration("20231204213851_ModifyDataTypes")] + partial class ModifyDataTypes + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("Unbinder.Models.Ingredient", b => + { + b.Property("IngredientId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("IngredientId")); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("IngredientId"); + + b.ToTable("Ingredients"); + }); + + modelBuilder.Entity("Unbinder.Models.Recipe", b => + { + b.Property("RecipeId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("RecipeId")); + + b.Property("Author") + .HasColumnType("nvarchar(max)"); + + b.Property("MainImageUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("RecipeText") + .HasColumnType("nvarchar(max)"); + + b.Property("S3Url") + .HasColumnType("nvarchar(max)"); + + b.Property("ShortDescription") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("RecipeId"); + + b.ToTable("Recipes"); + }); + + modelBuilder.Entity("Unbinder.Models.RecipeIngredient", b => + { + b.Property("RecipeIngredientId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("RecipeIngredientId")); + + b.Property("Amount") + .HasColumnType("float"); + + b.Property("IngredientId") + .HasColumnType("int"); + + b.Property("RecipeId") + .HasColumnType("int"); + + b.Property("Unit") + .HasColumnType("nvarchar(max)"); + + b.HasKey("RecipeIngredientId"); + + b.ToTable("RecipeIngredients"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Unbinder/Migrations/20231204213851_ModifyDataTypes.cs b/Unbinder/Migrations/20231204213851_ModifyDataTypes.cs new file mode 100644 index 0000000..3843a9d --- /dev/null +++ b/Unbinder/Migrations/20231204213851_ModifyDataTypes.cs @@ -0,0 +1,36 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Unbinder.Migrations +{ + /// + public partial class ModifyDataTypes : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "Amount", + table: "RecipeIngredients", + type: "float", + nullable: true, + oldClrType: typeof(string), + oldType: "nvarchar(max)", + oldNullable: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "Amount", + table: "RecipeIngredients", + type: "nvarchar(max)", + nullable: true, + oldClrType: typeof(double), + oldType: "float", + oldNullable: true); + } + } +} diff --git a/Unbinder/Migrations/UnbinderDbContextModelSnapshot.cs b/Unbinder/Migrations/UnbinderDbContextModelSnapshot.cs index b5bc5e5..77ce320 100644 --- a/Unbinder/Migrations/UnbinderDbContextModelSnapshot.cs +++ b/Unbinder/Migrations/UnbinderDbContextModelSnapshot.cs @@ -1,4 +1,5 @@ // +using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; @@ -9,7 +10,7 @@ using Unbinder.DB; namespace Unbinder.Migrations { - [DbContext(typeof(UnbinderDbContext))] + [DbContext(typeof(Initializer))] partial class UnbinderDbContextModelSnapshot : ModelSnapshot { protected override void BuildModel(ModelBuilder modelBuilder) @@ -82,8 +83,8 @@ namespace Unbinder.Migrations SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("RecipeIngredientId")); - b.Property("Amount") - .HasColumnType("nvarchar(max)"); + b.Property("Amount") + .HasColumnType("float"); b.Property("IngredientId") .HasColumnType("int"); diff --git a/Unbinder/Models/IngredientWithDetails.cs b/Unbinder/Models/IngredientWithDetails.cs new file mode 100644 index 0000000..14ab21e --- /dev/null +++ b/Unbinder/Models/IngredientWithDetails.cs @@ -0,0 +1,15 @@ +namespace Unbinder.Models +{ + public record IngredientWithDetails + { + + public Ingredient Ingredient { get; init; } = default!; + public IngredientDetails Details { get; init; } = default!; + } + + public record IngredientDetails + { + public double? Amount { get; init; } + public string? Unit { get; init; } + } +} diff --git a/Unbinder/Models/RecipeIngredient.cs b/Unbinder/Models/RecipeIngredient.cs index 1810874..23c4ba3 100644 --- a/Unbinder/Models/RecipeIngredient.cs +++ b/Unbinder/Models/RecipeIngredient.cs @@ -8,7 +8,7 @@ namespace Unbinder.Models public int RecipeIngredientId { get; init; } public int RecipeId { get; init; } public int IngredientId { get; init; } - public string? Amount { get; init; } + public double? Amount { get; init; } public string? Unit { get; init; } } } diff --git a/Unbinder/Program.cs b/Unbinder/Program.cs index a5192c7..121d6c9 100644 --- a/Unbinder/Program.cs +++ b/Unbinder/Program.cs @@ -46,6 +46,7 @@ builder.Services.AddCors(options => builder.Services.AddScoped(); builder.Services.AddScoped(); +builder.Services.AddScoped(); // include aws service builder.Services.AddTransient(); diff --git a/Unbinder/Repositories/IRecipeIngredientRepository.cs b/Unbinder/Repositories/IRecipeIngredientRepository.cs index 04835e2..94af6c0 100644 --- a/Unbinder/Repositories/IRecipeIngredientRepository.cs +++ b/Unbinder/Repositories/IRecipeIngredientRepository.cs @@ -4,5 +4,6 @@ namespace Unbinder.Repositories { public interface IRecipeIngredientRepository : IBaseRepository { + public IEnumerable? GetIngredientsByRecipeId(int recipeId); } } diff --git a/Unbinder/Repositories/RecipeIngredientRepository.cs b/Unbinder/Repositories/RecipeIngredientRepository.cs index 190d44c..645e04d 100644 --- a/Unbinder/Repositories/RecipeIngredientRepository.cs +++ b/Unbinder/Repositories/RecipeIngredientRepository.cs @@ -9,7 +9,7 @@ namespace Unbinder.Repositories public override IEnumerable? GetAll => null; public override RecipeIngredient? UpdateById(int id) => null; - // implemented methods: + // overridden methods: public override RecipeIngredient? GetById(int id) => _dbContext.RecipeIngredients.Where(ri => ri.RecipeIngredientId == id).FirstOrDefault(); public override RecipeIngredient Post(RecipeIngredient entity) @@ -27,5 +27,51 @@ namespace Unbinder.Repositories _dbContext.SaveChanges(); return 1; } + + // custom methods + public IEnumerable? GetIngredientsByRecipeId(int recipeId) + { + // get all ingredients associated with this recipe + var ingredientDetails = _dbContext.RecipeIngredients + .Where(ri => ri.RecipeId == recipeId) + .ToArray(); + + if (ingredientDetails == null) return null; + + // get the full DB listing for each ingredient + var ingredientsForRecipe = _dbContext.Ingredients + .Where(i => ingredientDetails.Select(d => d.IngredientId).Contains(i.IngredientId)) + .ToArray(); + + if (ingredientsForRecipe == null) return null; + + // combine the two into a merged output + return MergeIngredientsWithDetails(ingredientsForRecipe, ingredientDetails); + + } + + private static List MergeIngredientsWithDetails( + Ingredient[] ingredients, RecipeIngredient[] details) + { + List output = []; + + foreach (var ing in ingredients) + { + RecipeIngredient? CurrentDetails = details.Where(ri => + ri.IngredientId == ing.IngredientId).FirstOrDefault(); + + output.Add(new IngredientWithDetails + { + Ingredient = ing, + Details = new IngredientDetails + { + Amount = CurrentDetails?.Amount, + Unit = CurrentDetails?.Unit, + } + }); + } + + return output; + } } } diff --git a/Unbinder/Unbinder.csproj b/Unbinder/Unbinder.csproj index 3a21977..ea96bf1 100644 --- a/Unbinder/Unbinder.csproj +++ b/Unbinder/Unbinder.csproj @@ -28,7 +28,6 @@ - diff --git a/Unbinder/ViewModels/RecipeViewModel.cs b/Unbinder/ViewModels/RecipeViewModel.cs new file mode 100644 index 0000000..ddb31ed --- /dev/null +++ b/Unbinder/ViewModels/RecipeViewModel.cs @@ -0,0 +1,10 @@ +using Unbinder.Models; + +namespace Unbinder.ViewModels +{ + public class RecipeViewModel(Recipe _recipe, IEnumerable? _ingredients) + { + public Recipe Recipe { get; init; } = _recipe; + public IEnumerable? Ingredients { get; init; } = _ingredients; + } +} diff --git a/Unbinder/Views/Recipe/RecipeId.cshtml b/Unbinder/Views/Recipe/RecipeId.cshtml index 8ddc4c0..625c5ac 100644 --- a/Unbinder/Views/Recipe/RecipeId.cshtml +++ b/Unbinder/Views/Recipe/RecipeId.cshtml @@ -1,17 +1,48 @@ -@model Recipe +@model RecipeViewModel @{ var editMode = ViewBag.EditMode ?? false; + Recipe recipe = Model.Recipe; + IEnumerable? entries = Model.Ingredients; }
-

@Model.Name

-

@Model.ShortDescription

+

@recipe.Name

+

@recipe.ShortDescription

- @if (Model.RecipeText != null) + @if (entries != null) + { +
+

Ingredients:

+
+ @foreach (var entry in entries) + { + var measurementString = ""; + if (entry.Details.Amount != null) measurementString += entry.Details.Amount.ToString(); + if (entry.Details.Unit != null) measurementString += entry.Details.Unit; + +
+

@entry.Ingredient.Name -- @measurementString

+
+ + } +
+ +
+
+ } + + @if (recipe.RecipeText != null) {
-

@Model.RecipeText

+

@recipe.RecipeText

+
+ } + + @if (recipe.S3Url != null) + { +
+
}
\ No newline at end of file