Finished Project
This commit is contained in:
@@ -1,12 +1,12 @@
|
||||
namespace Francesco.Recipes.World.Views.Category
|
||||
{
|
||||
using Francesco.Recipes.World.Models;
|
||||
using Francesco.Recipes.World.Models.BackendModels.Category;
|
||||
using Francesco.Recipes.World.Models.BackendModels.Recipe;
|
||||
|
||||
public class CategoryRecipesViewModel
|
||||
{
|
||||
public Category Category { get; set; } = new ();
|
||||
|
||||
public IEnumerable<Recipe> Recipes { get; set; } = new List<Recipe>();
|
||||
public IEnumerable<RecipeCardViewModel> Recipes { get; set; } = new List<RecipeCardViewModel>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,39 +32,41 @@
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
@foreach (var recipe in category.Recipes)
|
||||
{
|
||||
var mediaFile = recipe.MediaFiles?.FirstOrDefault();
|
||||
var imageData = mediaFile?.Data;
|
||||
var mimeType = mediaFile?.MimeType;
|
||||
|
||||
<div class="col-md-3 mb-4">
|
||||
<div class="card h-100">
|
||||
<div class="recipe-image">
|
||||
@if (imageData != null && mimeType != null)
|
||||
{
|
||||
<img src="data:@mimeType;base64,@Convert.ToBase64String(imageData)" alt="@recipe.Name" class="card-img-top" />
|
||||
}
|
||||
else
|
||||
{
|
||||
<img src="/images/placeholder.png" alt="@recipe.Name" class="card-img-top" />
|
||||
}
|
||||
@foreach (var recipe in category.Recipes)
|
||||
{
|
||||
var imageData = recipe.ImageData;
|
||||
var mimeType = recipe.MimeType;
|
||||
|
||||
<div class="col-md-3 mb-4">
|
||||
<div class="card h-100">
|
||||
<div class="recipe-image">
|
||||
@if (imageData != null && mimeType != null)
|
||||
{
|
||||
<img src="data:@mimeType;base64,@Convert.ToBase64String(imageData)" alt="@recipe.Name" class="card-img-top" />
|
||||
}
|
||||
else
|
||||
{
|
||||
<img src="/images/placeholder.png" alt="@recipe.Name" class="card-img-top" />
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="card-body d-flex flex-column">
|
||||
<h5 class="card-title">@recipe.Name</h5>
|
||||
<p class="card-text text-muted mb-2">@recipe.CookingTime</p>
|
||||
<div id="favorite-button-@recipe.Id">
|
||||
@await Html.PartialAsync("_FavoriteButton", recipe)
|
||||
|
||||
</div>
|
||||
|
||||
<div class="card-body d-flex flex-column">
|
||||
<h5 class="card-title">@recipe.Name</h5>
|
||||
<p class="card-text text-muted mb-2">@recipe.CookingTime</p>
|
||||
|
||||
<div id="favorite-button-@recipe.Id">
|
||||
@await Html.PartialAsync("_FavoriteButton", recipe)
|
||||
</div>
|
||||
<a href="/Details/@recipe.Id"
|
||||
class="btn btn-primary mt-auto">Details</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<a href="/Details/@recipe.Id"
|
||||
class="btn btn-primary mt-auto">Details</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<div class="col-md-3 mb-4">
|
||||
<div class="card h-100 text-center">
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<a href="/Recipe/Details/@recipe.Id" class="btn btn-primary btn-sm">Details</a>
|
||||
<a href="/Details/@recipe.Id" class="btn btn-primary btn-sm">Details</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
@model IEnumerable<Francesco.Recipes.World.Views.Category.CategoryRecipesViewModel>
|
||||
|
||||
@{
|
||||
ViewData["Title"] = "Category Recipes";
|
||||
}
|
||||
|
||||
<h1>Category Recipes</h1>
|
||||
|
||||
@foreach (var categoryRecipes in Model)
|
||||
{
|
||||
<div class="category-section">
|
||||
<h2>@categoryRecipes.Category.Name</h2>
|
||||
<a asp-action="Create" asp-route-categoryId="@categoryRecipes.Category.Id" class="btn btn-primary">Rezept erstellen</a>
|
||||
<div class="recipes">
|
||||
@foreach (var recipe in categoryRecipes.Recipes)
|
||||
{
|
||||
<div class="recipe-card">
|
||||
<div class="recipe-image">
|
||||
@if (recipe.MediaFiles.Any() && recipe.MediaFiles.First().Data != null)
|
||||
{
|
||||
var mediaFile = recipe.MediaFiles.First();
|
||||
if (mediaFile.Data != null)
|
||||
{
|
||||
<img src="data:@mediaFile.MimeType;base64,@Convert.ToBase64String(mediaFile.Data)" alt="@recipe.Name" class="img-fluid" />
|
||||
}
|
||||
}
|
||||
</div>
|
||||
<div class="recipe-info">
|
||||
<h3>@recipe.Name</h3>
|
||||
<p>@recipe.Description</p>
|
||||
<p><strong>Difficulty:</strong> @recipe.Difficulty</p>
|
||||
<p><strong>Servings:</strong> @recipe.Servings</p>
|
||||
<p><strong>Preparation Time:</strong> @recipe.PreparationTime</p>
|
||||
<p><strong>Cooking Time:</strong> @recipe.CookingTime</p>
|
||||
<div class="recipe-favorite">
|
||||
@if (recipe.IsFavorite)
|
||||
{
|
||||
<form method="post" asp-action="RemoveFavorite" asp-controller="Recipe">
|
||||
<input type="hidden" name="recipeId" value="@recipe.Id" />
|
||||
<button type="submit" class="btn btn-danger">Remove from Favorites</button>
|
||||
</form>
|
||||
}
|
||||
else
|
||||
{
|
||||
<form method="post" asp-action="AddFavorite" asp-controller="Recipe">
|
||||
<input type="hidden" name="recipeId" value="@recipe.Id" />
|
||||
<button type="submit" class="btn btn-primary">Add to Favorites</button>
|
||||
</form>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div class="recipe-card add-recipe-card">
|
||||
<a asp-action="Create" asp-route-categoryId="@categoryRecipes.Category.Id" class="btn btn-primary">Rezept hinzufügen</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<style>
|
||||
.category-section {
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.recipes {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.recipe-card {
|
||||
width: 200px;
|
||||
margin: 1rem;
|
||||
padding: 1rem;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.recipe-image img {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.recipe-info {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.add-recipe-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: #f8f8f8;
|
||||
border: 2px dashed #ccc;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -107,7 +107,7 @@
|
||||
|
||||
<div class="text-center mt-4">
|
||||
<button type="submit" class="btn btn-success btn-lg">Rezept speichern</button>
|
||||
<a asp-action="Index" asp-controller="Category" class="btn btn-secondary btn-lg ml-2">Abbrechen</a>
|
||||
<a asp-action="Index" asp-controller="Home" class="btn btn-secondary btn-lg ml-2">Abbrechen</a>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
Instructions = Model.Instructions.ToList()
|
||||
})
|
||||
|
||||
<form hx-post="@($"/{Model.Id}/Delete")"
|
||||
<form hx-delete="@($"/{Model.Id}/Delete")"
|
||||
hx-confirm="Sind Sie sicher, dass Sie dieses Rezept löschen möchten? Diese Aktion kann nicht rückgängig gemacht werden."
|
||||
hx-redirect="/">
|
||||
@Html.AntiForgeryToken()
|
||||
@@ -173,34 +173,37 @@
|
||||
return Math.round(quantity * 10) / 10;
|
||||
}
|
||||
|
||||
window.addSelectedIngredientsToShoppingList = function(recipeIdParam) {
|
||||
const idToUse = recipeIdParam || recipeId;
|
||||
|
||||
window.addSelectedIngredientsToShoppingList = function(recipeIdParam) {
|
||||
const idToUse = recipeIdParam || recipeId;
|
||||
var form = document.getElementById('ingredient-form');
|
||||
var formData = new FormData(form);
|
||||
var selectedIngredientIds = formData.getAll('ingredientIds');
|
||||
|
||||
var form = document.getElementById('ingredient-form');
|
||||
var formData = new FormData(form);
|
||||
var selectedIngredientIds = formData.getAll('ingredientIds');
|
||||
fetch('/ShoppingList/CreateOrAddIngredients', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'RequestVerificationToken': document.querySelector('input[name="__RequestVerificationToken"]').value
|
||||
},
|
||||
body: JSON.stringify({ recipeId: idToUse, ingredientIds: selectedIngredientIds })
|
||||
})
|
||||
.then(response => {
|
||||
if (response.ok) {
|
||||
return response.json();
|
||||
}
|
||||
throw new Error('Failed to update shopping list');
|
||||
})
|
||||
.then(result => {
|
||||
localStorage.setItem('shoppingListId', result.shoppingListId);
|
||||
alert('Einkaufsliste aktualisiert.');
|
||||
})
|
||||
.catch(error => {
|
||||
alert('Fehler beim Aktualisieren der Einkaufsliste.');
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
var token = document.querySelector('input[name="__RequestVerificationToken"]').value;
|
||||
|
||||
var response = await fetch('/ShoppingList/CreateOrAddIngredients', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'RequestVerificationToken': token
|
||||
},
|
||||
body: JSON.stringify({ recipeId: '@Model.Id', ingredientIds: selectedIngredientIds })
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
var result = await response.json();
|
||||
localStorage.setItem('shoppingListId', result.shoppingListId);
|
||||
alert('Zutaten wurden zur Einkaufsliste hinzugefügt.');
|
||||
} else {
|
||||
alert('Fehler beim Hinzufügen zur Einkaufsliste.');
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@model Francesco.Recipes.World.Models.BackendModels.Recipe.Recipe
|
||||
@model Francesco.Recipes.World.Models.IFavoritable
|
||||
|
||||
<form hx-post="@Url.Action(Model.IsFavorite ? "RemoveFavorite" : "AddFavorite", "Recipe")"
|
||||
hx-target="this"
|
||||
|
||||
@@ -36,3 +36,4 @@
|
||||
|
||||
|
||||
|
||||
<script src="~/js/site.js" asp-append-version="true" defer></script>
|
||||
|
||||
@@ -21,13 +21,9 @@
|
||||
}
|
||||
</select>
|
||||
<button type="button" class="btn-delete" onclick="Francesco.removeIngredient('@Model.Ingredients[i].Id')">🗑️</button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<button type="button" class="btn-add" onclick="Francesco.addIngredient()">Zutat hinzufügen</button>
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -23,17 +23,12 @@
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Startseite</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-controller="Recipes" asp-action="Index">Rezepte</a>
|
||||
<a class="nav-link text-dark" asp-area="" asp-controller="ShoppingList" asp-action="Details">Einkaufsliste</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-controller="Category" asp-action="Index">Kategorien</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-controller="ShoppingList" asp-action="Index">Einkaufsliste</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-controller="Favorites" asp-action="Index">Favoriten</a>
|
||||
<a class="nav-link text-dark" asp-area="" asp-controller="Favorite" asp-action="Index">Favoriten</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="d-flex">
|
||||
|
||||
Reference in New Issue
Block a user