From a140a59f66b16a77f3738978b256c1bb29d4204a Mon Sep 17 00:00:00 2001 From: Elias Jansson Date: Tue, 6 May 2025 13:19:13 +0200 Subject: [PATCH] Menu - Pre 9 .net --- Aberwyn/Aberwyn.csproj | 2 +- Aberwyn/Controllers/FoodMenuController.cs | 184 +++++++---- Aberwyn/Controllers/MealController.cs | 69 +++- Aberwyn/Controllers/MealMenuApiController.cs | 38 +-- Aberwyn/Data/MenuService.cs | 100 ++++-- Aberwyn/Models/MenuViewModel.cs | 9 +- Aberwyn/Models/WeeklyMenuViewModel.cs | 16 +- Aberwyn/Program.cs | 36 ++- Aberwyn/Views/FoodMenu/Veckomeny.cshtml | 302 +++++++++++++----- Aberwyn/Views/Home/Menu.cshtml | 123 ++++--- Aberwyn/Views/Meal/Meal.cshtml | 2 +- Aberwyn/Views/Meal/View.cshtml | 196 +++++++++--- Aberwyn/Views/Meal/_MealTooltip.cshtml | 8 + Aberwyn/wwwroot/css/meal-menu.css | 4 + .../21f12523-36e9-451f-b120-d9cac21061fe.png | Bin 0 -> 4278 bytes .../fc8aff8c-4bef-45a8-9e40-7b78f76f04e8.png | Bin ...s_75ac2dd7-1115-43c3-b5fd-2829bf2395de.png | Bin 0 -> 4278 bytes ...t_93c95185-81d2-4b9b-9286-39c7dcd0ddb1.png | Bin 0 -> 4588 bytes Aberwyn/wwwroot/js/menu.js | 138 ++++---- 19 files changed, 849 insertions(+), 378 deletions(-) create mode 100644 Aberwyn/Views/Meal/_MealTooltip.cshtml create mode 100644 Aberwyn/wwwroot/images/21f12523-36e9-451f-b120-d9cac21061fe.png rename Aberwyn/wwwroot/{uploads => images}/fc8aff8c-4bef-45a8-9e40-7b78f76f04e8.png (100%) create mode 100644 Aberwyn/wwwroot/images/meals/mcdonalds_75ac2dd7-1115-43c3-b5fd-2829bf2395de.png create mode 100644 Aberwyn/wwwroot/images/meals/test_93c95185-81d2-4b9b-9286-39c7dcd0ddb1.png diff --git a/Aberwyn/Aberwyn.csproj b/Aberwyn/Aberwyn.csproj index 08e1112..6466970 100644 --- a/Aberwyn/Aberwyn.csproj +++ b/Aberwyn/Aberwyn.csproj @@ -31,7 +31,7 @@ - + diff --git a/Aberwyn/Controllers/FoodMenuController.cs b/Aberwyn/Controllers/FoodMenuController.cs index 663b057..ad23c37 100644 --- a/Aberwyn/Controllers/FoodMenuController.cs +++ b/Aberwyn/Controllers/FoodMenuController.cs @@ -1,7 +1,14 @@ using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Hosting; using Aberwyn.Models; using Aberwyn.Data; +using System; using System.Globalization; +using System.Linq; +using System.Collections.Generic; +using System.Text.RegularExpressions; namespace Aberwyn.Controllers { @@ -16,35 +23,89 @@ namespace Aberwyn.Controllers _env = env; } - public IActionResult Veckomeny(int week = -1) + public IActionResult Veckomeny(int? week, int? year) { var menuService = new MenuService(_configuration, _env); - int currentWeek = week == -1 ? ISOWeek.GetWeekOfYear(DateTime.Now) : week; - int currentYear = DateTime.Now.Year; - // Hämta meny frćn DB - var menus = menuService.GetWeeklyMenu(currentWeek, currentYear); + var today = DateTime.Today; + int resolvedWeek = week ?? ISOWeek.GetWeekOfYear(today); + int resolvedYear = year ?? today.Year; - var model = new WeeklyMenuViewModel + var menus = menuService.GetWeeklyMenu(resolvedWeek, resolvedYear); + + var vm = new WeeklyMenuViewModel { - WeekNumber = currentWeek, - Year = currentYear, + WeekNumber = resolvedWeek, + Year = resolvedYear, WeeklyMenus = menus, AvailableCooks = menuService.GetUsers() }; - return View(model); + var recent = menuService + .GetMenuEntriesByDateRange(DateTime.Now.AddDays(-28), DateTime.Now) + .Select(x => new WeeklyMenuViewModel.RecentMenuEntry + { + Date = x.Date, + BreakfastMealName = x.BreakfastMealName, + LunchMealName = x.LunchMealName, + DinnerMealName = x.DinnerMealName + }) + .ToList(); + + vm.RecentEntries = recent; + ViewBag.AvailableMeals = menuService.GetMeals(); + + return View(vm); + } + + [HttpPost] + public IActionResult AddMealAjax([FromBody] Meal meal) + { + if (meal == null || string.IsNullOrWhiteSpace(meal.Name)) + return BadRequest("Ogiltigt mćltidsobjekt."); + + var service = new MenuService(_configuration, _env); + + // Kontrollera om en mćltid med samma namn redan finns + var existing = service.GetMeals() + .FirstOrDefault(m => m.Name.Equals(meal.Name, StringComparison.OrdinalIgnoreCase)); + + if (existing == null) + { + // Fyll i CreatedAt om det inte sätts automatiskt i databasen + meal.CreatedAt = DateTime.Now; + service.SaveOrUpdateMeal(meal); + existing = meal; + } + else + { + // Om mćltiden finns men saknar data (t.ex. är bara ett namn) kan vi uppdatera den + existing.Description = meal.Description; + existing.ProteinType = meal.ProteinType; + existing.CarbType = meal.CarbType; + existing.RecipeUrl = meal.RecipeUrl; + existing.ImageUrl = meal.ImageUrl; + service.SaveOrUpdateMeal(existing); + } + + return Json(new + { + Id = existing.Id, + Name = existing.Name, + Description = existing.Description, + ProteinType = existing.ProteinType, + CarbType = existing.CarbType, + RecipeUrl = existing.RecipeUrl + }); } public IActionResult MealAdmin() { var service = new MenuService(_configuration, _env); - var meals = service.GetMealsDetailed(); // Se till att denna metod finns och returnerar fullständiga Meal-objekt + var meals = service.GetMealsDetailed(); return View("MealAdmin", meals); } - - [HttpGet] public JsonResult SearchMeals(string term) { @@ -64,17 +125,16 @@ namespace Aberwyn.Controllers return Json(result); } - [HttpPost] - public IActionResult SaveVeckomeny(IFormCollection form) + public IActionResult SaveVeckomeny(IFormCollection form, int week, int year) { var menuService = new MenuService(_configuration, _env); var allMeals = menuService.GetMeals(); var model = new MenuViewModel { - WeekNumber = ISOWeek.GetWeekOfYear(DateTime.Now), - Year = DateTime.Now.Year, + WeekNumber = week, + Year = year, WeeklyMenus = new List() }; @@ -82,62 +142,76 @@ namespace Aberwyn.Controllers foreach (var key in form.Keys.Where(k => k.StartsWith("Meal[", StringComparison.OrdinalIgnoreCase))) { - var match = System.Text.RegularExpressions.Regex.Match(key, @"Meal\[(\d+)\]\[(\w+)\]"); - if (match.Success) + var match = Regex.Match(key, @"Meal\[(\d+)\]\[(\w+)\]"); + if (!match.Success) continue; + + int day = int.Parse(match.Groups[1].Value); + string mealType = match.Groups[2].Value; + string mealName = form[key]; + string cook = form[$"Cook[{day}]"]; + + if (!entriesByDay.TryGetValue(day, out var entry)) { - int day = int.Parse(match.Groups[1].Value); - string mealType = match.Groups[2].Value; - - string mealName = form[key]; - string cook = form[$"Cook[{day}][{mealType}]"]; - - if (string.IsNullOrWhiteSpace(mealName)) continue; - - var meal = allMeals.FirstOrDefault(m => m.Name.Equals(mealName, StringComparison.OrdinalIgnoreCase)); - if (meal == null) + entry = new WeeklyMenu { - meal = new Meal { Name = mealName }; - menuService.SaveMeal(meal); + WeekNumber = week, + Year = year, + DayOfWeek = day + 1 + }; + entriesByDay[day] = entry; + } + + entry.Cook = cook; + + if (string.IsNullOrWhiteSpace(mealName)) + { + switch (mealType.ToLower()) + { + case "lunch": + entry.LunchMealId = null; + entry.LunchMealName = null; + break; + case "middag": + entry.DinnerMealId = null; + entry.DinnerMealName = null; + break; + case "frukost": + entry.BreakfastMealId = null; + entry.BreakfastMealName = null; + break; } + continue; + } - if (!entriesByDay.TryGetValue(day, out var entry)) - { - entry = new WeeklyMenu - { - WeekNumber = model.WeekNumber, - Year = model.Year - }; - entriesByDay[day] = entry; - } + var meal = allMeals.FirstOrDefault(m => m.Name.Equals(mealName, StringComparison.OrdinalIgnoreCase)) + ?? new Meal { Name = mealName }; - entry.DayOfWeek = day + 1; // se till att alltid sätta rätt dag - entry.Cook = cook; + if (meal.Id == 0) + menuService.SaveOrUpdateMeal(meal); - if (mealType.Equals("Lunch", StringComparison.OrdinalIgnoreCase)) - { + switch (mealType.ToLower()) + { + case "lunch": entry.LunchMealId = meal.Id; entry.LunchMealName = meal.Name; - } - else if (mealType.Equals("Middag", StringComparison.OrdinalIgnoreCase)) - { + break; + case "middag": entry.DinnerMealId = meal.Id; entry.DinnerMealName = meal.Name; - } - else if (mealType.Equals("Frukost", StringComparison.OrdinalIgnoreCase)) - { + break; + case "frukost": entry.BreakfastMealId = meal.Id; entry.BreakfastMealName = meal.Name; - } + break; } } model.WeeklyMenus = entriesByDay.Values.ToList(); menuService.UpdateWeeklyMenu(model); - return RedirectToAction("Veckomeny"); + return RedirectToAction("Veckomeny", new { week, year }); } + + } - - - - } \ No newline at end of file +} diff --git a/Aberwyn/Controllers/MealController.cs b/Aberwyn/Controllers/MealController.cs index 8007f35..3d3d35a 100644 --- a/Aberwyn/Controllers/MealController.cs +++ b/Aberwyn/Controllers/MealController.cs @@ -15,16 +15,62 @@ namespace Aberwyn.Controllers _env = env; } [HttpGet] - public IActionResult View(int id) + public IActionResult View(int id, bool edit = false) { var service = new MenuService(_configuration, _env); var meal = service.GetMealById(id); + + ViewData["IsEditing"] = edit; // → hĂ€r + if (meal == null) + { return NotFound(); + } return View("View", meal); } + [HttpGet] + [Route("Meal/Tooltip/{id}")] + public IActionResult Tooltip(int id) + { + try + { + var service = new MenuService(_configuration, _env); + var meal = service.GetMealById(id); + + if (meal == null) + return Content("
Hittade ingen rÀtt.
", "text/html"); + + // Se till att Description aldrig Ă€r null + var desc = meal.Description ?? ""; + + // Gör en kort beskrivning + var shortDesc = desc.Length > 100 + ? desc.Substring(0, 100) + "
" + : desc; + + // Bygg upp en enkel HTML-snutt + var html = + $"
" + + $" {meal.Name}
" + + (string.IsNullOrWhiteSpace(shortDesc) + ? "Ingen beskrivning tillgÀnglig." + : $"{shortDesc}") + + "
"; + + return Content(html, "text/html"); + } + catch (Exception ex) + { + // För felsökning kan du logga ex.Message, men för tillfÀllet returnera det sÄ vi ser det i devtools + return StatusCode(500, $"
{ex.Message}
"); + } + } + + + + [HttpGet] public IActionResult Edit(int? id) { @@ -34,30 +80,33 @@ namespace Aberwyn.Controllers } [HttpPost] - public async Task SaveMeal(Meal meal, IFormFile ImageFile) + public IActionResult SaveMeal(Meal meal, IFormFile ImageFile) { var service = new MenuService(_configuration, _env); if (ImageFile != null && ImageFile.Length > 0) { - var uploadsFolder = Path.Combine(_env.ContentRootPath, "wwwroot/uploads"); - Directory.CreateDirectory(uploadsFolder); // skapa om saknas - var uniqueFileName = Guid.NewGuid().ToString() + Path.GetExtension(ImageFile.FileName); - var filePath = Path.Combine(uploadsFolder, uniqueFileName); + var fileName = Path.GetFileNameWithoutExtension(ImageFile.FileName); + var extension = Path.GetExtension(ImageFile.FileName); + var uniqueName = $"{fileName}_{Guid.NewGuid()}{extension}"; + var imagePath = Path.Combine("wwwroot/images/meals", uniqueName); - using (var fileStream = new FileStream(filePath, FileMode.Create)) + using (var stream = new FileStream(imagePath, FileMode.Create)) { - await ImageFile.CopyToAsync(fileStream); + ImageFile.CopyTo(stream); } - meal.ImageUrl = "/uploads/" + uniqueFileName; + // Spara relativ sökvĂ€g för visning + meal.ImageUrl = $"/images/meals/{uniqueName}"; } service.SaveOrUpdateMeal(meal); - return RedirectToAction("Edit", new { id = meal.Id }); + + return RedirectToAction("View", new { id = meal.Id }); } + [HttpPost] public IActionResult DeleteMeal(int id) { diff --git a/Aberwyn/Controllers/MealMenuApiController.cs b/Aberwyn/Controllers/MealMenuApiController.cs index 5a503ab..6fd5a72 100644 --- a/Aberwyn/Controllers/MealMenuApiController.cs +++ b/Aberwyn/Controllers/MealMenuApiController.cs @@ -2,6 +2,8 @@ using Aberwyn.Models; using Aberwyn.Data; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Hosting; namespace Aberwyn.Controllers { @@ -11,71 +13,45 @@ namespace Aberwyn.Controllers { private readonly MenuService _menuService; - public MealMenuApiController(MenuService menuService) + public MealMenuApiController(IConfiguration configuration, IHostEnvironment env) { - _menuService = menuService; + _menuService = new MenuService(configuration, env); } - // API endpoint to fetch the weekly menu [HttpGet("menu")] public IActionResult GetMenu(int weekNumber, int year) { var menu = _menuService.GetWeeklyMenu(weekNumber, year); - - if (menu == null || !menu.Any()) - { - // Return an empty object or array instead of a 404 error - return Ok(new List()); // Return empty list if no menu is found - } - - return Ok(menu); // Return the menu as a JSON response + return Ok(menu ?? new List()); } - // API endpoint to fetch the weekly menu [HttpGet("getMeals")] public IActionResult GetMeals() { var meals = _menuService.GetMeals(); - - if (meals == null || !meals.Any()) - { - // Return an empty object or array instead of a 404 error - return Ok(new List()); // Return empty list if no menu is found - } - - return Ok(meals); // Return the menu as a JSON response + return Ok(meals ?? new List()); } - // API endpoint to save the updated menu (if you need this) [HttpPut("menu")] public IActionResult SaveMenu([FromBody] MenuViewModel weeklyMenu) { - // Process and save the menu (you may need to write this logic) _menuService.UpdateWeeklyMenu(weeklyMenu); - return Ok("Menu saved successfully"); } - [HttpPost("addMeal")] public IActionResult AddMeal([FromBody] Meal meal) { if (meal == null || string.IsNullOrWhiteSpace(meal.Name)) - { return BadRequest("Meal Name is required."); - } + // AnvĂ€nd AddMeal som returnerar det nya ID:t var mealId = _menuService.AddMeal(meal); if (mealId > 0) - { return Ok(new { Message = "Meal added successfully", MealId = mealId }); - } return StatusCode(500, "Failed to add meal."); } - - - } } diff --git a/Aberwyn/Data/MenuService.cs b/Aberwyn/Data/MenuService.cs index e3c923c..1fe5b7e 100644 --- a/Aberwyn/Data/MenuService.cs +++ b/Aberwyn/Data/MenuService.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; using Aberwyn.Models; +using System.Globalization; namespace Aberwyn.Data { @@ -197,7 +198,7 @@ namespace Aberwyn.Data using var connection = GetConnection(); connection.Open(); - string query = @"SELECT Id, Name, Description, ProteinType, CarbType, RecipeUrl, CreatedAt + string query = @"SELECT Id, Name, Description, ProteinType, CarbType, RecipeUrl, CreatedAt, ImageUrl FROM Meals WHERE Id = @id"; using var cmd = new MySqlCommand(query, connection); @@ -214,6 +215,7 @@ namespace Aberwyn.Data ProteinType = reader.IsDBNull(reader.GetOrdinal("ProteinType")) ? null : reader.GetString(reader.GetOrdinal("ProteinType")), CarbType = reader.IsDBNull(reader.GetOrdinal("CarbType")) ? null : reader.GetString(reader.GetOrdinal("CarbType")), RecipeUrl = reader.IsDBNull(reader.GetOrdinal("RecipeUrl")) ? null : reader.GetString(reader.GetOrdinal("RecipeUrl")), + ImageUrl = reader.IsDBNull(reader.GetOrdinal("ImageUrl")) ? null : reader.GetString(reader.GetOrdinal("ImageUrl")), CreatedAt = reader.GetDateTime(reader.GetOrdinal("CreatedAt")) }; @@ -234,44 +236,48 @@ namespace Aberwyn.Data public void SaveOrUpdateMeal(Meal meal) { - using var connection = GetConnection(); - connection.Open(); + using var conn = new MySqlConnection(_configuration.GetConnectionString("DefaultConnection")); + conn.Open(); - string query; - bool isNew = meal.Id == 0; - - if (isNew) + using var cmd = conn.CreateCommand(); + if (meal.Id == 0) { - query = @"INSERT INTO Meals (Name, Description, ProteinType, CarbType, RecipeUrl, CreatedAt) - VALUES (@name, @desc, @protein, @carb, @url, @created)"; + cmd.CommandText = @"INSERT INTO Meals + (Name, Description, ProteinType, CarbType, RecipeUrl, CreatedAt, ImageUrl) + VALUES (@Name, @Description, @ProteinType, @CarbType, @RecipeUrl, @CreatedAt, @ImageUrl); + SELECT LAST_INSERT_ID();"; } else { - query = @"UPDATE Meals - SET Name = @name, Description = @desc, ProteinType = @protein, CarbType = @carb, RecipeUrl = @url - WHERE Id = @id"; + cmd.CommandText = @"UPDATE Meals + SET Name = @Name, Description = @Description, ProteinType = @ProteinType, + CarbType = @CarbType, RecipeUrl = @RecipeUrl, ImageUrl = @ImageUrl + WHERE Id = @Id"; + cmd.Parameters.AddWithValue("@Id", meal.Id); } - using var cmd = new MySqlCommand(query, connection); - cmd.Parameters.AddWithValue("@name", meal.Name); - cmd.Parameters.AddWithValue("@desc", meal.Description ?? ""); - cmd.Parameters.AddWithValue("@protein", meal.ProteinType ?? ""); - cmd.Parameters.AddWithValue("@carb", meal.CarbType ?? ""); - cmd.Parameters.AddWithValue("@url", meal.RecipeUrl ?? ""); + cmd.Parameters.AddWithValue("@Name", meal.Name ?? ""); + cmd.Parameters.AddWithValue("@Description", meal.Description ?? ""); + cmd.Parameters.AddWithValue("@ProteinType", meal.ProteinType ?? ""); + cmd.Parameters.AddWithValue("@CarbType", meal.CarbType ?? ""); + cmd.Parameters.AddWithValue("@RecipeUrl", meal.RecipeUrl ?? ""); + cmd.Parameters.AddWithValue("@CreatedAt", meal.CreatedAt == default ? DateTime.Now : meal.CreatedAt); + cmd.Parameters.AddWithValue("@ImageUrl", meal.ImageUrl ?? ""); - if (isNew) + if (meal.Id == 0) { - cmd.Parameters.AddWithValue("@created", meal.CreatedAt == default ? DateTime.Now : meal.CreatedAt); + var insertedId = Convert.ToInt32(cmd.ExecuteScalar()); + meal.Id = insertedId; // ← SĂ€tt ID direkt pĂ„ objektet } else { - cmd.Parameters.AddWithValue("@id", meal.Id); + cmd.ExecuteNonQuery(); } - - cmd.ExecuteNonQuery(); } + + public void UpdateWeeklyMenu(MenuViewModel menuData) { if (menuData == null || menuData.WeeklyMenus == null) @@ -384,6 +390,54 @@ namespace Aberwyn.Data _ => throw new System.ArgumentException("Invalid day name") }; } + public List GetMenuEntriesByDateRange(DateTime startDate, DateTime endDate) + { + var results = new List(); + + // Hitta start- och slut-Ă„r/veckonummer + int startWeek = ISOWeek.GetWeekOfYear(startDate); + int startYear = startDate.Year; + int endWeek = ISOWeek.GetWeekOfYear(endDate); + int endYear = endDate.Year; + + // Loopar över alla veckor frĂ„n start → slut + var allMenus = new List(); + int w = startWeek, y = startYear; + while (y < endYear || (y == endYear && w <= endWeek)) + { + allMenus.AddRange(GetWeeklyMenu(w, y)); + + // öka vecka, hantera Ă„rsskifte + int weeksInYear = ISOWeek.GetWeeksInYear(y); + if (w == weeksInYear) + { + w = 1; + y++; + } + else + { + w++; + } + } + + // Filtrera pĂ„ datumintervall + foreach (var menu in allMenus) + { + // Konvertera DayOfWeek (1=Mon
7=Sun) till System.DayOfWeek + var dow = (DayOfWeek)(menu.DayOfWeek % 7); + var date = ISOWeek.ToDateTime(menu.Year, menu.WeekNumber, dow); + + if (date.Date >= startDate.Date && date.Date <= endDate.Date) + { + menu.Date = date; // Se till att WeeklyMenu har en Date-property + results.Add(menu); + } + } + + return results; + } + + } } diff --git a/Aberwyn/Models/MenuViewModel.cs b/Aberwyn/Models/MenuViewModel.cs index 525edce..dba83cd 100644 --- a/Aberwyn/Models/MenuViewModel.cs +++ b/Aberwyn/Models/MenuViewModel.cs @@ -24,9 +24,16 @@ namespace Aberwyn.Models public string BreakfastMealName { get; set; } // 👈 Och denna public string LunchMealName { get; set; } public string DinnerMealName { get; set; } + public DateTime Date { get; set; } } - + public class RecentMenuEntry + { + public DateTime Date { get; set; } + public string BreakfastMealName { get; set; } + public string LunchMealName { get; set; } + public string DinnerMealName { get; set; } + } public class Meal { public int Id { get; set; } diff --git a/Aberwyn/Models/WeeklyMenuViewModel.cs b/Aberwyn/Models/WeeklyMenuViewModel.cs index 6f7b2d8..fdb7bb8 100644 --- a/Aberwyn/Models/WeeklyMenuViewModel.cs +++ b/Aberwyn/Models/WeeklyMenuViewModel.cs @@ -5,18 +5,30 @@ using System.Linq; namespace Aberwyn.Models { + public class WeeklyMenuViewModel { public int WeekNumber { get; set; } public int Year { get; set; } + public List RecentEntries { get; set; } = new(); public List WeeklyMenus { get; set; } = new(); public List AvailableCooks { get; set; } = new(); + // Ny lista för översikt + public List PreviousWeeks { get; set; } = new(); + public class RecentMenuEntry + { + public DateTime Date { get; set; } + public string BreakfastMealName { get; set; } + public string LunchMealName { get; set; } + public string DinnerMealName { get; set; } + } + + public WeeklyMenu GetMealEntry(int day, string type) { int dayOfWeek = day + 1; - return WeeklyMenus.FirstOrDefault(m => m.DayOfWeek == dayOfWeek && ( @@ -27,4 +39,6 @@ namespace Aberwyn.Models ); } } + + } diff --git a/Aberwyn/Program.cs b/Aberwyn/Program.cs index 82a20e6..115ec82 100644 --- a/Aberwyn/Program.cs +++ b/Aberwyn/Program.cs @@ -1,28 +1,36 @@ -using Microsoft.EntityFrameworkCore; // Add this for DbContext -using Aberwyn.Data; // Include your data namespace -using MySql.EntityFrameworkCore.Extensions; // For MySQL support +using Microsoft.EntityFrameworkCore; +using Aberwyn.Data; +using MySql.EntityFrameworkCore.Extensions; using System.Text; using System.Globalization; using Microsoft.AspNetCore.Localization; +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; var builder = WebApplication.CreateBuilder(args); // Add services to the container. -builder.Services.AddControllersWithViews(); -builder.Services.AddRazorPages(); // Add this line to enable Razor Pages -builder.Services.AddHttpClient(); // Register HttpClient +builder.Services.AddControllersWithViews() + .AddJsonOptions(opts => + { + // Behćll propertynamn som i C#-klassen (PascalCase) + opts.JsonSerializerOptions.PropertyNamingPolicy = null; + // Ignorera null-värden vid serialisering + opts.JsonSerializerOptions.IgnoreNullValues = true; + }); +builder.Services.AddRazorPages(); +builder.Services.AddHttpClient(); // Configure your DbContext with MySQL builder.Services.AddDbContext(options => options.UseMySQL(builder.Configuration.GetConnectionString("BudgetDb"))); - -// Register your BudgetService with a scoped lifetime +// Register your services builder.Services.AddScoped(); builder.Services.AddScoped(); - Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); builder.Services.Configure(options => { @@ -31,6 +39,7 @@ builder.Services.Configure(options => options.SupportedCultures = supportedCultures; options.SupportedUICultures = supportedCultures; }); + var app = builder.Build(); // Configure the HTTP request pipeline. @@ -40,20 +49,19 @@ if (!app.Environment.IsDevelopment()) app.UseHsts(); } -//app.UseHttpsRedirection(); app.UseStaticFiles(); - app.UseRouting(); - app.UseAuthorization(); +// Map controller endpoints (including AJAX JSON actions) +app.MapControllers(); -// Map default controller route +// Conventional MVC route app.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); // Map Razor Pages -app.MapRazorPages(); // Add this line to map Razor Pages +app.MapRazorPages(); app.Run(); diff --git a/Aberwyn/Views/FoodMenu/Veckomeny.cshtml b/Aberwyn/Views/FoodMenu/Veckomeny.cshtml index 975068a..d6306a9 100644 --- a/Aberwyn/Views/FoodMenu/Veckomeny.cshtml +++ b/Aberwyn/Views/FoodMenu/Veckomeny.cshtml @@ -1,93 +1,229 @@ -@model WeeklyMenuViewModel +@using System.Globalization +@model Aberwyn.Models.WeeklyMenuViewModel @{ ViewData["Title"] = "Veckomeny"; var days = new[] { "MĂ„ndag", "Tisdag", "Onsdag", "Torsdag", "Fredag", "Lördag", "Söndag" }; - var mealTypes = new[] { "Frukost", "Lunch", "Middag" }; + var allMeals = ViewBag.AvailableMeals as List; } -

Veckomeny - Vecka @Model.WeekNumber

+ -
- FöregÄende vecka - NÀsta vecka + + + + +
+ + + + +
+

Veckomeny - Vecka @Model.WeekNumber

+
+ ← FöregĂ„ende vecka + Vecka @Model.WeekNumber + NĂ€sta vecka → +
+ +
+ + + + + + + + + + + + @for (int i = 0; i < 7; i++) { + var dinnerEntry = Model.GetMealEntry(i, "Middag"); + var lunchEntry = Model.GetMealEntry(i, "Lunch"); + var breakfastEntry = Model.GetMealEntry(i, "Frukost"); + + + + + + + + + + + + } + +
DagMiddagKock
+ + @days[i] + +
+ + +
+
+ +
+
+
+ + + +
+
+ + + +
+
+
+ + +
+ +
+ + + @foreach(var m in ViewBag.AvailableMeals as List) { + + } + +
-
- - - - - @foreach (var mealType in mealTypes) - { - - } - - - - @for (int i = 0; i < 7; i++) - { - - - @foreach (var mealType in mealTypes) - { - var entry = Model.GetMealEntry(i, mealType); - var mealName = mealType switch - { - "Frukost" => entry?.BreakfastMealName, - "Lunch" => entry?.LunchMealName, - "Middag" => entry?.DinnerMealName, - _ => null - }; - - } - - } - - - -
- -@section Scripts { - - -} diff --git a/Aberwyn/Views/Home/Menu.cshtml b/Aberwyn/Views/Home/Menu.cshtml index ef2c6c1..1ef2936 100644 --- a/Aberwyn/Views/Home/Menu.cshtml +++ b/Aberwyn/Views/Home/Menu.cshtml @@ -1,54 +1,97 @@ ï»ż@model Aberwyn.Models.MenuViewModel @{ - // Define a flag to hide the sidebar if the URL path matches '/nosidebar' (relative part after the controller) - bool hideSidebar = Context.Request.Path.Value.EndsWith("/nosidebar", StringComparison.OrdinalIgnoreCase); - Layout = hideSidebar ? null : "_Layout"; // No layout if the path ends with '/nosidebar' + var hideSidebar = Context.Request.Path.Value.EndsWith("/nosidebar", StringComparison.OrdinalIgnoreCase); + Layout = hideSidebar ? null : "_Layout"; } - - + - - Meal Menu Overview + + Veckomeny + + + - + + + - + +
+

Veckomeny

-
-

Meal Menu Overview

- -
- - Vecka {{ selectedWeek }} - {{ selectedYear }} - -
- -
-
-
{{ day }}
- -
-
-
- Frukost: {{ menu[day].breakfastMealName }} -
-
- Lunch: {{ menu[day].lunchMealName }} -
-
- Middag: {{ menu[day].dinnerMealName }} -
-
-
- Inte bestÀmd -
-
-
-
+ +
+ + Vecka {{selectedWeek}} – {{selectedYear}} +
+ + +
+ + +
+ + +
+ + +
+
+
+
+
{{day}}
+
Frukost: {{menu[day].breakfastMealName}}
+
Lunch: {{menu[day].lunchMealName}}
+
Middag: {{menu[day].dinnerMealName}}
+
Inte bestÀmd
+
+
+
+
+
+
diff --git a/Aberwyn/Views/Meal/Meal.cshtml b/Aberwyn/Views/Meal/Meal.cshtml index 2dac870..e9560f1 100644 --- a/Aberwyn/Views/Meal/Meal.cshtml +++ b/Aberwyn/Views/Meal/Meal.cshtml @@ -40,7 +40,7 @@
- +
diff --git a/Aberwyn/Views/Meal/View.cshtml b/Aberwyn/Views/Meal/View.cshtml index a2230f5..f97fb44 100644 --- a/Aberwyn/Views/Meal/View.cshtml +++ b/Aberwyn/Views/Meal/View.cshtml @@ -1,90 +1,192 @@ ï»ż@model Aberwyn.Models.Meal @{ ViewData["Title"] = Model.Name; + bool isEditing = (bool)(ViewData["IsEditing"] ?? false); + var imageUrl = string.IsNullOrEmpty(Model.ImageUrl) ? "/images/placeholder-meal.jpg" : Model.ImageUrl; }
-

@Model.Name

- - @if (!string.IsNullOrEmpty(Model.ImageUrl)) - { - @Model.Name - } - - @if (!string.IsNullOrEmpty(Model.Description)) - { -

@Model.Description

- } - -
- - Redigera +
+ @Model.Name +
+

@Model.Name

+

@Model.Description

+
- diff --git a/Aberwyn/Views/Meal/_MealTooltip.cshtml b/Aberwyn/Views/Meal/_MealTooltip.cshtml new file mode 100644 index 0000000..d587e43 --- /dev/null +++ b/Aberwyn/Views/Meal/_MealTooltip.cshtml @@ -0,0 +1,8 @@ +ï»ż@model dynamic +
+ @Model.Name
+ @Model.ShortDescription
+ @if (Model.Ingredients != null) { +
Ingredienser: @String.Join(", ", Model.Ingredients)
+ } +
diff --git a/Aberwyn/wwwroot/css/meal-menu.css b/Aberwyn/wwwroot/css/meal-menu.css index d263455..eab75de 100644 --- a/Aberwyn/wwwroot/css/meal-menu.css +++ b/Aberwyn/wwwroot/css/meal-menu.css @@ -208,3 +208,7 @@ .new-meal-form button:hover { background-color: #F57C00; } + +.meal-hover { + cursor: pointer; +} diff --git a/Aberwyn/wwwroot/images/21f12523-36e9-451f-b120-d9cac21061fe.png b/Aberwyn/wwwroot/images/21f12523-36e9-451f-b120-d9cac21061fe.png new file mode 100644 index 0000000000000000000000000000000000000000..116c3be89d36c3ff6a557efcdcad965238f9c99e GIT binary patch literal 4278 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 literal 0 HcmV?d00001 diff --git a/Aberwyn/wwwroot/uploads/fc8aff8c-4bef-45a8-9e40-7b78f76f04e8.png b/Aberwyn/wwwroot/images/fc8aff8c-4bef-45a8-9e40-7b78f76f04e8.png similarity index 100% rename from Aberwyn/wwwroot/uploads/fc8aff8c-4bef-45a8-9e40-7b78f76f04e8.png rename to Aberwyn/wwwroot/images/fc8aff8c-4bef-45a8-9e40-7b78f76f04e8.png diff --git a/Aberwyn/wwwroot/images/meals/mcdonalds_75ac2dd7-1115-43c3-b5fd-2829bf2395de.png b/Aberwyn/wwwroot/images/meals/mcdonalds_75ac2dd7-1115-43c3-b5fd-2829bf2395de.png new file mode 100644 index 0000000000000000000000000000000000000000..116c3be89d36c3ff6a557efcdcad965238f9c99e GIT binary patch literal 4278 zcma)=_ahVz1IEuP&fbTRmEE0l?qoY>M`wqO%gD+Wnepu+GiC3cy)shf${!Hr=FrJ*;^B1%5RK=Rkr1FbU!~ z;;=^tfRF>og8>TSKz>kQ2WeL6E0VfP3ORYH(&X$SrkA4s}&)jNC0% zD0xH!09OU5OLHKl8BxlBdy2K`%4{e}fGk+Y6u#M`MV^$qqay`SybU#$cJ+ovK3DoD zLcu!-YHSBlGMD!EP@1jNJ{r~h(Rp7?S9szR@?C;@Y?zL^$?cDY`eFz{IZct$d~MQ* z!F-cqOb|FX1^O1N)Lo^At5NPR)=2WETE6lG!Mx;%sU8M9&C%9b_vwVctayH z!bY3u#qfoa5C2%~kMT3)cf*`h#j0GxwY8%=VTA>Gv%kqvN^E*=5IuvdZ*jj>en+|| z4LL{JcrMhox)z~(9U&lw8~^nEfA}hsC?o%Ta`ORB{%c`2^dP_|po96L-7M^KW%nzw zzm+V=#*+-&9{+XZ=tJIUtcHUIhcD<0V1fH?CqK6~8cm^!*$%@hWT;C2?`Go3H?uPP z$<{Un5<0KF&M*|OlkWjqsp52`##qbN2N z+_Sl%`PRsTWKngK6$_*IGB4;spMPE$?V#LR1ckqX!5KkF8|#J%!HLm&vW6QdB^LGq zm$2V_#Aifu*(hnD-I!8U?m^$@RiYNkS$|^TJ@HXswo<^hOQT@wL%h}d%!R#8z+PuH zXsm;+_2~dNDvsLMxQ37SEMHm)a-y==y`IDPMq&T!FRG*ADW7MfhoilRm+BWL^Gb^& zD%8$>M;rs`CM_rHDv*6fr-1XY4Z{i=w{>(~cD{okEz4B2kBuPNX-qfbn5eGb8$73_ z%1lFm==&vY}|7d*AF_Vp}YZ_r$T1kJ$&LA4rUhsTv+ zI0w} zi@wuAyUY0(|7}5p>h*S79vE6ceuWd9PfzJs?W@j44!qX*pWhV%a=Vm$-B`Xd%^Fbj zNv$kV^TUzw%3fd#rn^?mFSu(pF$2p>!cI``WZuoBXgOf z$>oINP9PRpN{nWD@70wOGj8cQbeMF%h6PXNuM@RNs-RDEwBpQX-f?xZ_V-P$yOokT z2@K3N>k(e@8G2paqX9P9S`4wgQcTX)c$sg?y`<}5*Ge^@(Mi|&B)5(rdq@4Dw;k=) zjc~PAX^!oj!{h;~0TtfdOmT!mR;lw1rt~u-HtX2yh6PS>TI3XL@|4)@1@hW)|M>02 zsdvD>71V(QTOJ^7Yww%WYtEw&y3J4!|9#H(QBWL`9Bag#c+S1?EO)FK10u~s2C00W zh7x>VkqmumS+Z)3)J`xJ5v)vz2=OkG>s*K-1J_ZXj;9G5bZWAg=WZJ_-)u_0eB$W2 zboA|A@yW%<*TRDT=qiC&PHKNsuK{?H4#x5l$TCwuqkHL_FS}2i-$RP`|V|y;#f3x7MBVVuc51_5k1OtF3o6v zinz8Qj|!(gG+3ClVQ!oFDiG8WL8T)-PT}h3w9t?!ZW0iGWS8#TMm*ZZT*L$_eXa@E zPv>9^eq!k^;C1#?y^v>|)+XQIbMTdp!YVj!J^sLoVV-Y@I@QQie)_E^GY(5Da}vq( zD<|WVz#W^CN`@a_&qcsQf!-Cgdk7(5plDFu&qBUK+Kxg-#1Z>n6dn+ z8q`Ka0XOd{2_jfjeDP>LvS|?L4yadnHu#FcRyG-KhglT^3DH$GZC^;z3fWP@-3e>W9xXR3S@zVPZy83nrJM zs|<7lJZ@MXEVSnM_4jYGsNY_69ujAB(N)v=GUoB`+S*QCZD}Jc&GUwSsbK%GYbM?z zZ);xL8*mQzewN1;{=jxyI_-MQ?B5&+07-G&YFF9K%i6qr+s?M5H~MTHX#E*{pTkD^ zcZCQ7&Mc|~0}9m|Ur%kV`Rshv-?nW^JqFJ1Ai3vH0><`X}W;>Q-s z0bUZJ`cJdGwdk(QlZ89o$HJ3cy@*T-+0AEa?xVyGSPjb~Q@ST^{ws|9g&AMzqs)`V zL3K%EBXiN`HTjLI2M4%X-1>Wu8RH@yJ2UkUzZV$Pbg{pvz@f{4PaZSTT_o!_t{eut zx#O4pOEcEyK9@iDDhGG77Qc~RBPHx=K9tXb+K$Jmd6A)6mFN}jElk+HWioJ{N+?H( zMQPcql^dC_@v{x-5+=VH4O;!g4qi+!C;+ZJF); z_l+#DTKd#Lh@zUyl;D>qtbg`+tT#2`>P7oVihwI$b?azCHmHXoyA}8CTi)fKPOiXn zw~fmq-gVdc?oYY%X2jR9;)r4+x!fQCBM^XEt%g?HA9C)$Pe0Z=9z>5)`25ZG0Rb_*ztoZm?5%6m zPkps>5r2~avChoP?Jyd>()A|(bS#-Ne`b~}|NN{a7RVvy+hM8aua@C#a5r&TJ>D$b z7fcCF^_<^r!nl!5PnVZOIVPm#3zCEgU8coU{3-O~!G0dj+ z?8)?&{C7{Eue;%mq@CXFUrYhtcAs2T)4%ZSjO37h>3z>gD9pJSNF!nA?hcp9&wj~% zNgfsI-)1##nCISIM8*p>6&Y!YLO8_*^=dAu;k)0)&Xxnc0$bH{;4_#1c?6jY8N zdWiwnI0G{a-EVdWpXB97AyYoboW!?Zd;eywlY1 zvyZ#CX*fVf6DZFV3AGm+_+m zapl6*zIKK`O*15eisBe7 zSx%z0QsPtEw5_zzdm1F+L4ogozfJTTBJe_8+>JH}Q!`ysFO2m)*AIIS4T&CPn{ZR< zkInMseu0vyy5_1BYeCvO-^;UsEBrKamo(|RW9Ilm(}xD?RI`gT&YuC6;vzGZ{Gt}I znE{iN$GLxaJko^I1+EXZD4ySL3CzG~opo}nvs}2za$^z3w+#D&?%4^2iQXQ|c;y4- zAPTUltAEUyN$66q1h;ck+!^{)A1fn+T%L?069qi_Hz({S{@PkA7jOCA^d2QtiF`gN zcF#>~?I%!eM{7veY5V)62}m|Emdi_#(!h$M+8zn(ni-kh+9_MLPoDqFHD650g5?o! z^;)BGyO(Vb;06u~u^DQ+sK%BJHY}%y&}Xiv$s2pz!B3T8c1Jm zVZM3xU0t<*f7dh+w=3P641YIKt5s=OHi*cV!QR43lx^IEker*?_b0~Xpf20s5C z?w{TmN(6eC+d~%K#UB_vT&7mnm^=SLHi~f1;N?k!d%4L^n`iP;(=>;@uCX$6X`grhW@IcHYb!HA5{_E>f{{$`nH3lg#oL1M=Hjj z%|e2*ePWFGpz!+l`ED!CJkGfYvdpXtWIs;+I}oKIYs?=omt;vIL`9H@c=Cs$1Rm$Q zaMg}S?EtKOu+wgexE1+o?6{{6JQ(L})@4~nYxXGsn`fWb*;T0WoTPKce!jB!o|I|5 z7OfoP(rP75i%ZTAd4CC>mT>rIIwg8#G}&vZJS zDoFjP51R=uEfP95Hqngfb<1gE5OnC_OQe){l8KzgdyST^p5?x4zmDE$#YW{qU;8im pOyEPwVpo)E|NkcapIP=Zs=hT0{ArTj{=a_&KwsM!RgZLx`47do8x;Tm literal 0 HcmV?d00001 diff --git a/Aberwyn/wwwroot/images/meals/test_93c95185-81d2-4b9b-9286-39c7dcd0ddb1.png b/Aberwyn/wwwroot/images/meals/test_93c95185-81d2-4b9b-9286-39c7dcd0ddb1.png new file mode 100644 index 0000000000000000000000000000000000000000..e39e4c9d5e07f02a2ce71e07cf0263dd9dce8e50 GIT binary patch literal 4588 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 WgJOR{w { - $scope.meals = response.data; + console.log("HĂ€mtar mĂ„ltider..."); + return $http.get('/api/mealMenuApi/getMeals') + .then(res => { + console.log("MĂ„ltider hĂ€mtade:", res.data); + $scope.meals = res.data; + return res; }) - .catch(error => console.error("Error fetching meals:", error)); + .catch(err => console.error("Fel vid hĂ€mtning av mĂ„ltider:", err)); }; $scope.loadMenu = function () { + console.log("HĂ€mtar meny för vecka:", $scope.selectedWeek, $scope.selectedYear); $http.get('/api/mealMenuApi/menu', { params: { weekNumber: $scope.selectedWeek, year: $scope.selectedYear } - }).then(response => { - console.log("Veckomenydata:", response.data); // ✅ logga ut - + }).then(res => { + console.log("Menyposter hĂ€mtade:", res.data); $scope.menu = {}; - response.data.forEach(item => { - const dayOfWeek = $scope.daysOfWeek[item.dayOfWeek - 1]; - if (!$scope.menu[dayOfWeek]) $scope.menu[dayOfWeek] = {}; - if (item.breakfastMealId) { - $scope.menu[dayOfWeek].breakfastMealId = item.breakfastMealId; - $scope.menu[dayOfWeek].breakfastMealName = getMealNameById(item.breakfastMealId); - } - if (item.lunchMealId) { - $scope.menu[dayOfWeek].lunchMealId = item.lunchMealId; - $scope.menu[dayOfWeek].lunchMealName = getMealNameById(item.lunchMealId); - } - if (item.dinnerMealId) { - $scope.menu[dayOfWeek].dinnerMealId = item.dinnerMealId; - $scope.menu[dayOfWeek].dinnerMealName = getMealNameById(item.dinnerMealId); + res.data.forEach(item => { + const dayIndex = item.DayOfWeek - 1; + if (dayIndex < 0 || dayIndex >= $scope.daysOfWeek.length) { + console.warn("Ogiltig dag:", item.DayOfWeek); + return; } + + const day = $scope.daysOfWeek[dayIndex]; + $scope.menu[day] = {}; + + ['breakfast', 'lunch', 'dinner'].forEach(type => { + // Konvertera till PascalCase + const capitalType = type.charAt(0).toUpperCase() + type.slice(1); + const idKey = capitalType + 'MealId'; + const nameKey = capitalType + 'MealName'; + + if (item[idKey]) { + const m = $scope.meals.find(x => x.Id === item[idKey]); + console.log(`Match för ${type} (${day}):`, m); + + $scope.menu[day][type + 'MealId'] = item[idKey]; + $scope.menu[day][type + 'MealName'] = m?.Name || item[nameKey] || 'OkĂ€nd rĂ€tt'; + + if (m?.ImageUrl) { + $scope.menu[day].imageUrl = m.ImageUrl; + } + } + }); }); - }).catch(error => console.error("Error fetching weekly menu:", error)); + + console.log("Byggd meny:", $scope.menu); + }).catch(err => console.error("Fel vid hĂ€mtning av veckomeny:", err)); }; - function getMealNameById(mealId) { - const meal = $scope.meals.find(m => m.id === mealId); - return meal ? meal.name : "Unknown Meal"; - } - - $scope.handleMealSelection = function (day, mealType) { - if ($scope.menu[day][mealType + "MealId"] === "new") { - $scope.showNewMealForm = true; - $scope.newMeal = { name: "", description: "", proteinType: "", carbType: "", recipeUrl: "" }; - $scope.selectedMealDay = day; - $scope.selectedMealType = mealType; - } + $scope.openMeal = function (mealId) { + if (!mealId) return; + window.open('/Meal/View/' + mealId, '_blank'); }; - $scope.saveNewMeal = function () { - if (!$scope.newMeal.name) { - alert("Meal name is required"); - return; - } - $http.post('/api/mealMenuApi/addMeal', $scope.newMeal) - .then(response => { - const addedMeal = response.data; - $scope.meals.push(addedMeal); - $scope.menu[$scope.selectedMealDay][$scope.selectedMealType + "MealId"] = addedMeal.id; - $scope.showNewMealForm = false; - $scope.newMeal = {}; // Reset new meal data after save - }) - .catch(error => console.error("Error saving new meal:", error)); + $scope.getDayImage = function (day) { + const item = $scope.menu[day]; + return (item && item.imageUrl) || '/images/default-meal.jpg'; }; - $scope.cancelNewMeal = function () { - $scope.showNewMealForm = false; - $scope.newMeal = {}; // Reset new meal data when canceled + $scope.getMealIdByDay = function (day) { + const item = $scope.menu[day] || {}; + return item.dinnerMealId || item.lunchMealId || item.breakfastMealId || null; }; - function getWeek(date) { - const day = date.getDay() || 7; - date.setDate(date.getDate() + 4 - day); - const yearStart = new Date(date.getFullYear(), 0, 1); - return Math.ceil(((date - yearStart) / 86400000 + 1) / 7); - } - $scope.goToPreviousWeek = function () { if ($scope.selectedWeek === 1) { $scope.selectedYear--; @@ -114,6 +99,17 @@ $scope.loadMenu(); }; - $scope.loadMeals(); - $scope.loadMenu(); + function getWeek(d) { + d = new Date(d.getFullYear(), d.getMonth(), d.getDate()); + const dayNum = d.getDay() || 7; + d.setDate(d.getDate() + 4 - dayNum); + const yearStart = new Date(d.getFullYear(), 0, 1); + return Math.ceil((((d - yearStart) / 86400000) + 1) / 7); + } + + console.log("Initierar mĂ„ltidsladdning..."); + $scope.loadMeals().then(() => { + console.log("Laddar meny efter mĂ„ltider..."); + $scope.loadMenu(); + }); });