Menu stuff
This commit is contained in:
@@ -3,12 +3,12 @@
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<UseAppHost>false</UseAppHost>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<UserSecretsId>d748f28f-7908-4174-b2a1-c21d4d06499f</UserSecretsId>
|
||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="NewFolder\**" />
|
||||
<Content Remove="NewFolder\**" />
|
||||
@@ -29,4 +29,9 @@
|
||||
<PackageReference Include="MySql.EntityFrameworkCore" Version="8.0.5" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Views\NewFolder\" />
|
||||
<Folder Include="wwwroot\uploads\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
BIN
Aberwyn/Aberwyn_Veckomeny_v1.zip
Normal file
BIN
Aberwyn/Aberwyn_Veckomeny_v1.zip
Normal file
Binary file not shown.
143
Aberwyn/Controllers/FoodMenuController.cs
Normal file
143
Aberwyn/Controllers/FoodMenuController.cs
Normal file
@@ -0,0 +1,143 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Aberwyn.Models;
|
||||
using Aberwyn.Data;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Aberwyn.Controllers
|
||||
{
|
||||
public class FoodMenuController : Controller
|
||||
{
|
||||
private readonly IConfiguration _configuration;
|
||||
private readonly IHostEnvironment _env;
|
||||
|
||||
public FoodMenuController(IConfiguration configuration, IHostEnvironment env)
|
||||
{
|
||||
_configuration = configuration;
|
||||
_env = env;
|
||||
}
|
||||
|
||||
public IActionResult Veckomeny(int week = -1)
|
||||
{
|
||||
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 model = new WeeklyMenuViewModel
|
||||
{
|
||||
WeekNumber = currentWeek,
|
||||
Year = currentYear,
|
||||
WeeklyMenus = menus,
|
||||
AvailableCooks = menuService.GetUsers()
|
||||
};
|
||||
|
||||
return View(model);
|
||||
}
|
||||
|
||||
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
|
||||
return View("MealAdmin", meals);
|
||||
}
|
||||
|
||||
|
||||
|
||||
[HttpGet]
|
||||
public JsonResult SearchMeals(string term)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(term))
|
||||
return Json(new List<string>());
|
||||
|
||||
var menuService = new MenuService(_configuration, _env);
|
||||
var meals = menuService.GetMeals();
|
||||
|
||||
var result = meals
|
||||
.Where(m => m.Name != null && m.Name.Contains(term, StringComparison.OrdinalIgnoreCase))
|
||||
.Select(m => m.Name)
|
||||
.Distinct()
|
||||
.Take(10)
|
||||
.ToList();
|
||||
|
||||
return Json(result);
|
||||
}
|
||||
|
||||
|
||||
[HttpPost]
|
||||
public IActionResult SaveVeckomeny(IFormCollection form)
|
||||
{
|
||||
var menuService = new MenuService(_configuration, _env);
|
||||
var allMeals = menuService.GetMeals();
|
||||
|
||||
var model = new MenuViewModel
|
||||
{
|
||||
WeekNumber = ISOWeek.GetWeekOfYear(DateTime.Now),
|
||||
Year = DateTime.Now.Year,
|
||||
WeeklyMenus = new List<WeeklyMenu>()
|
||||
};
|
||||
|
||||
var entriesByDay = new Dictionary<int, WeeklyMenu>();
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
meal = new Meal { Name = mealName };
|
||||
menuService.SaveMeal(meal);
|
||||
}
|
||||
|
||||
if (!entriesByDay.TryGetValue(day, out var entry))
|
||||
{
|
||||
entry = new WeeklyMenu
|
||||
{
|
||||
WeekNumber = model.WeekNumber,
|
||||
Year = model.Year
|
||||
};
|
||||
entriesByDay[day] = entry;
|
||||
}
|
||||
|
||||
entry.DayOfWeek = day + 1; // se till att alltid sätta rätt dag
|
||||
entry.Cook = cook;
|
||||
|
||||
if (mealType.Equals("Lunch", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
entry.LunchMealId = meal.Id;
|
||||
entry.LunchMealName = meal.Name;
|
||||
}
|
||||
else if (mealType.Equals("Middag", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
entry.DinnerMealId = meal.Id;
|
||||
entry.DinnerMealName = meal.Name;
|
||||
}
|
||||
else if (mealType.Equals("Frukost", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
entry.BreakfastMealId = meal.Id;
|
||||
entry.BreakfastMealName = meal.Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
model.WeeklyMenus = entriesByDay.Values.ToList();
|
||||
menuService.UpdateWeeklyMenu(model);
|
||||
|
||||
return RedirectToAction("Veckomeny");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -39,6 +39,8 @@ namespace Aberwyn.Controllers
|
||||
|
||||
public IActionResult Menu()
|
||||
{
|
||||
|
||||
ViewData["HideSidebar"] = true;
|
||||
// Get the current date and week
|
||||
var currentDate = DateTime.Now;
|
||||
var currentYear = currentDate.Year;
|
||||
|
||||
69
Aberwyn/Controllers/MealController.cs
Normal file
69
Aberwyn/Controllers/MealController.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Aberwyn.Models;
|
||||
using Aberwyn.Data;
|
||||
|
||||
namespace Aberwyn.Controllers
|
||||
{
|
||||
public class MealController : Controller
|
||||
{
|
||||
private readonly IConfiguration _configuration;
|
||||
private readonly IHostEnvironment _env;
|
||||
|
||||
public MealController(IConfiguration configuration, IHostEnvironment env)
|
||||
{
|
||||
_configuration = configuration;
|
||||
_env = env;
|
||||
}
|
||||
[HttpGet]
|
||||
public IActionResult View(int id)
|
||||
{
|
||||
var service = new MenuService(_configuration, _env);
|
||||
var meal = service.GetMealById(id);
|
||||
if (meal == null)
|
||||
return NotFound();
|
||||
|
||||
return View("View", meal);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public IActionResult Edit(int? id)
|
||||
{
|
||||
var service = new MenuService(_configuration, _env);
|
||||
var meal = id.HasValue ? service.GetMealById(id.Value) : new Meal();
|
||||
return View("Meal", meal);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<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);
|
||||
|
||||
using (var fileStream = new FileStream(filePath, FileMode.Create))
|
||||
{
|
||||
await ImageFile.CopyToAsync(fileStream);
|
||||
}
|
||||
|
||||
meal.ImageUrl = "/uploads/" + uniqueFileName;
|
||||
}
|
||||
|
||||
service.SaveOrUpdateMeal(meal);
|
||||
return RedirectToAction("Edit", new { id = meal.Id });
|
||||
}
|
||||
|
||||
|
||||
[HttpPost]
|
||||
public IActionResult DeleteMeal(int id)
|
||||
{
|
||||
var service = new MenuService(_configuration, _env);
|
||||
//service.DeleteMeal(id);
|
||||
return RedirectToAction("Edit"); // eller tillbaka till lista
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,65 @@ namespace Aberwyn.Data
|
||||
|
||||
return new MySqlConnection(connectionString);
|
||||
}
|
||||
public List<User> GetUsers()
|
||||
{
|
||||
var users = new List<User>();
|
||||
using (var connection = GetConnection())
|
||||
{
|
||||
connection.Open();
|
||||
string query = @"SELECT userID, Username, Name FROM Nevyn.tblUsers WHERE Chef = 1";
|
||||
|
||||
using (var cmd = new MySqlCommand(query, connection))
|
||||
using (var reader = cmd.ExecuteReader())
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
users.Add(new User
|
||||
{
|
||||
UserID = reader.GetInt32("userID"),
|
||||
Username = reader.GetString("Username"),
|
||||
Name = reader.GetString("Name")
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return users;
|
||||
}
|
||||
|
||||
public void SaveMeal(Meal meal)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(meal?.Name))
|
||||
return;
|
||||
|
||||
meal.Name = meal.Name.Trim();
|
||||
|
||||
using var connection = GetConnection();
|
||||
connection.Open();
|
||||
|
||||
var query = @"
|
||||
INSERT INTO Meals
|
||||
(Name, Description, RecipeUrl, CreatedAt)
|
||||
VALUES (@name, @desc, @url, CURRENT_TIMESTAMP);";
|
||||
|
||||
using var cmd = new MySqlCommand(query, connection);
|
||||
cmd.Parameters.AddWithValue("@name", meal.Name);
|
||||
cmd.Parameters.AddWithValue("@desc", meal.Description ?? "");
|
||||
cmd.Parameters.AddWithValue("@url", meal.RecipeUrl ?? "");
|
||||
|
||||
try
|
||||
{
|
||||
cmd.ExecuteNonQuery();
|
||||
meal.Id = (int)cmd.LastInsertedId;
|
||||
}
|
||||
catch (MySqlException ex) when (ex.Number == 1062)
|
||||
{
|
||||
Console.WriteLine($"⚠️ Måltiden '{meal.Name}' finns redan i databasen.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"❌ Fel vid sparning av måltid '{meal.Name}': {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public List<WeeklyMenu> GetWeeklyMenu(int weekNumber, int year)
|
||||
{
|
||||
@@ -33,12 +92,16 @@ namespace Aberwyn.Data
|
||||
{
|
||||
connection.Open();
|
||||
string query = @"
|
||||
SELECT wm.Id, wm.DayOfWeek, wm.DinnerMealId, wm.LunchMealId, wm.WeekNumber, wm.Year,
|
||||
dm.Name AS DinnerMealName, lm.Name AS LunchMealName
|
||||
FROM WeeklyMenu wm
|
||||
LEFT JOIN Meals dm ON wm.DinnerMealId = dm.Id
|
||||
LEFT JOIN Meals lm ON wm.LunchMealId = lm.Id
|
||||
WHERE wm.WeekNumber = @weekNumber AND wm.Year = @year";
|
||||
SELECT wm.Id, wm.DayOfWeek, wm.DinnerMealId, wm.LunchMealId, wm.BreakfastMealId,
|
||||
wm.WeekNumber, wm.Year, wm.Cook,
|
||||
dm.Name AS DinnerMealName,
|
||||
lm.Name AS LunchMealName,
|
||||
bm.Name AS BreakfastMealName
|
||||
FROM WeeklyMenu wm
|
||||
LEFT JOIN Meals dm ON wm.DinnerMealId = dm.Id
|
||||
LEFT JOIN Meals lm ON wm.LunchMealId = lm.Id
|
||||
LEFT JOIN Meals bm ON wm.BreakfastMealId = bm.Id
|
||||
WHERE wm.WeekNumber = @weekNumber AND wm.Year = @year";
|
||||
|
||||
using (var cmd = new MySqlCommand(query, connection))
|
||||
{
|
||||
@@ -53,13 +116,15 @@ namespace Aberwyn.Data
|
||||
{
|
||||
Id = reader.GetInt32("Id"),
|
||||
DayOfWeek = reader.GetInt32("DayOfWeek"),
|
||||
DinnerMealId = reader.IsDBNull(reader.GetOrdinal("DinnerMealId")) ? (int?)null : reader.GetInt32("DinnerMealId"),
|
||||
LunchMealId = reader.IsDBNull(reader.GetOrdinal("LunchMealId")) ? (int?)null : reader.GetInt32("LunchMealId"),
|
||||
DinnerMealId = reader.IsDBNull(reader.GetOrdinal("DinnerMealId")) ? (int?)null : reader.GetInt32(reader.GetOrdinal("DinnerMealId")),
|
||||
LunchMealId = reader.IsDBNull(reader.GetOrdinal("LunchMealId")) ? (int?)null : reader.GetInt32(reader.GetOrdinal("LunchMealId")),
|
||||
BreakfastMealId = reader.IsDBNull(reader.GetOrdinal("BreakfastMealId")) ? (int?)null : reader.GetInt32(reader.GetOrdinal("BreakfastMealId")),
|
||||
WeekNumber = reader.GetInt32("WeekNumber"),
|
||||
Year = reader.GetInt32("Year"),
|
||||
DinnerMealName = reader.IsDBNull(reader.GetOrdinal("DinnerMealName")) ? null : reader.GetString("DinnerMealName"),
|
||||
LunchMealName = reader.IsDBNull(reader.GetOrdinal("LunchMealName")) ? null : reader.GetString("LunchMealName"),
|
||||
|
||||
Cook = reader.IsDBNull(reader.GetOrdinal("Cook")) ? null : reader.GetString(reader.GetOrdinal("Cook")),
|
||||
DinnerMealName = reader.IsDBNull(reader.GetOrdinal("DinnerMealName")) ? null : reader.GetString(reader.GetOrdinal("DinnerMealName")),
|
||||
LunchMealName = reader.IsDBNull(reader.GetOrdinal("LunchMealName")) ? null : reader.GetString(reader.GetOrdinal("LunchMealName")),
|
||||
BreakfastMealName = reader.IsDBNull(reader.GetOrdinal("BreakfastMealName")) ? null : reader.GetString(reader.GetOrdinal("BreakfastMealName"))
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -68,6 +133,7 @@ namespace Aberwyn.Data
|
||||
return weeklyMenu;
|
||||
}
|
||||
|
||||
|
||||
public List<Meal> GetMeals()
|
||||
{
|
||||
var meals = new List<Meal>();
|
||||
@@ -92,6 +158,119 @@ namespace Aberwyn.Data
|
||||
}
|
||||
return meals;
|
||||
}
|
||||
public List<Meal> GetMealsDetailed()
|
||||
{
|
||||
var meals = new List<Meal>();
|
||||
|
||||
using (var connection = GetConnection())
|
||||
{
|
||||
connection.Open();
|
||||
string query = @"
|
||||
SELECT Id, Name, Description, ProteinType, CarbType, RecipeUrl, CreatedAt
|
||||
FROM Meals
|
||||
ORDER BY CreatedAt DESC";
|
||||
|
||||
using (var cmd = new MySqlCommand(query, connection))
|
||||
using (var reader = cmd.ExecuteReader())
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
meals.Add(new Meal
|
||||
{
|
||||
Id = reader.GetInt32(reader.GetOrdinal("Id")),
|
||||
Name = reader.GetString(reader.GetOrdinal("Name")),
|
||||
Description = reader.IsDBNull(reader.GetOrdinal("Description")) ? null : reader.GetString(reader.GetOrdinal("Description")),
|
||||
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")),
|
||||
CreatedAt = reader.GetDateTime(reader.GetOrdinal("CreatedAt"))
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return meals;
|
||||
}
|
||||
|
||||
public Meal GetMealById(int id)
|
||||
{
|
||||
using var connection = GetConnection();
|
||||
connection.Open();
|
||||
|
||||
string query = @"SELECT Id, Name, Description, ProteinType, CarbType, RecipeUrl, CreatedAt
|
||||
FROM Meals WHERE Id = @id";
|
||||
|
||||
using var cmd = new MySqlCommand(query, connection);
|
||||
cmd.Parameters.AddWithValue("@id", id);
|
||||
|
||||
using var reader = cmd.ExecuteReader();
|
||||
if (reader.Read())
|
||||
{
|
||||
return new Meal
|
||||
{
|
||||
Id = reader.GetInt32(reader.GetOrdinal("Id")),
|
||||
Name = reader.GetString(reader.GetOrdinal("Name")),
|
||||
Description = reader.IsDBNull(reader.GetOrdinal("Description")) ? null : reader.GetString(reader.GetOrdinal("Description")),
|
||||
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")),
|
||||
CreatedAt = reader.GetDateTime(reader.GetOrdinal("CreatedAt"))
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void DeleteMeal(int id)
|
||||
{
|
||||
using var connection = GetConnection();
|
||||
connection.Open();
|
||||
string query = "DELETE FROM Meals WHERE Id = @id";
|
||||
using var cmd = new MySqlCommand(query, connection);
|
||||
cmd.Parameters.AddWithValue("@id", id);
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
|
||||
public void SaveOrUpdateMeal(Meal meal)
|
||||
{
|
||||
using var connection = GetConnection();
|
||||
connection.Open();
|
||||
|
||||
string query;
|
||||
bool isNew = meal.Id == 0;
|
||||
|
||||
if (isNew)
|
||||
{
|
||||
query = @"INSERT INTO Meals (Name, Description, ProteinType, CarbType, RecipeUrl, CreatedAt)
|
||||
VALUES (@name, @desc, @protein, @carb, @url, @created)";
|
||||
}
|
||||
else
|
||||
{
|
||||
query = @"UPDATE Meals
|
||||
SET Name = @name, Description = @desc, ProteinType = @protein, CarbType = @carb, RecipeUrl = @url
|
||||
WHERE Id = @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 ?? "");
|
||||
|
||||
if (isNew)
|
||||
{
|
||||
cmd.Parameters.AddWithValue("@created", meal.CreatedAt == default ? DateTime.Now : meal.CreatedAt);
|
||||
}
|
||||
else
|
||||
{
|
||||
cmd.Parameters.AddWithValue("@id", meal.Id);
|
||||
}
|
||||
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
|
||||
|
||||
public void UpdateWeeklyMenu(MenuViewModel menuData)
|
||||
{
|
||||
@@ -105,33 +284,50 @@ namespace Aberwyn.Data
|
||||
{
|
||||
try
|
||||
{
|
||||
// Loop over each WeeklyMenu in the WeeklyMenus list
|
||||
foreach (var weeklyMenu in menuData.WeeklyMenus)
|
||||
foreach (var menu in menuData.WeeklyMenus)
|
||||
{
|
||||
int dayOfWeek = weeklyMenu.DayOfWeek;
|
||||
var menu = weeklyMenu;
|
||||
int dayOfWeek = menu.DayOfWeek;
|
||||
|
||||
// SQL query to update the existing records
|
||||
string query = @"
|
||||
string updateQuery = @"
|
||||
UPDATE WeeklyMenu
|
||||
SET
|
||||
DinnerMealId = @dinnerMealId,
|
||||
BreakfastMealId = @breakfastMealId,
|
||||
LunchMealId = @lunchMealId,
|
||||
DinnerMealId = @dinnerMealId,
|
||||
Cook = @cook
|
||||
WHERE DayOfWeek = @dayOfWeek
|
||||
AND WeekNumber = @weekNumber
|
||||
AND Year = @year;";
|
||||
|
||||
using (var cmd = new MySqlCommand(query, connection, transaction))
|
||||
using (var cmd = new MySqlCommand(updateQuery, connection, transaction))
|
||||
{
|
||||
cmd.Parameters.AddWithValue("@dayOfWeek", dayOfWeek);
|
||||
cmd.Parameters.AddWithValue("@dinnerMealId", menu.DinnerMealId ?? (object)DBNull.Value);
|
||||
cmd.Parameters.AddWithValue("@breakfastMealId", menu.BreakfastMealId ?? (object)DBNull.Value);
|
||||
cmd.Parameters.AddWithValue("@lunchMealId", menu.LunchMealId ?? (object)DBNull.Value);
|
||||
cmd.Parameters.AddWithValue("@dinnerMealId", menu.DinnerMealId ?? (object)DBNull.Value);
|
||||
cmd.Parameters.AddWithValue("@weekNumber", menu.WeekNumber);
|
||||
cmd.Parameters.AddWithValue("@year", menu.Year);
|
||||
cmd.Parameters.AddWithValue("@cook", menu.Cook ?? (object)DBNull.Value);
|
||||
|
||||
cmd.ExecuteNonQuery();
|
||||
int rowsAffected = cmd.ExecuteNonQuery();
|
||||
|
||||
if (rowsAffected == 0)
|
||||
{
|
||||
string insertQuery = @"
|
||||
INSERT INTO WeeklyMenu
|
||||
(DayOfWeek, WeekNumber, Year, BreakfastMealId, LunchMealId, DinnerMealId, Cook)
|
||||
VALUES (@dayOfWeek, @weekNumber, @year, @breakfastMealId, @lunchMealId, @dinnerMealId, @cook);";
|
||||
|
||||
using var insertCmd = new MySqlCommand(insertQuery, connection, transaction);
|
||||
insertCmd.Parameters.AddWithValue("@dayOfWeek", dayOfWeek);
|
||||
insertCmd.Parameters.AddWithValue("@breakfastMealId", menu.BreakfastMealId ?? (object)DBNull.Value);
|
||||
insertCmd.Parameters.AddWithValue("@lunchMealId", menu.LunchMealId ?? (object)DBNull.Value);
|
||||
insertCmd.Parameters.AddWithValue("@dinnerMealId", menu.DinnerMealId ?? (object)DBNull.Value);
|
||||
insertCmd.Parameters.AddWithValue("@weekNumber", menu.WeekNumber);
|
||||
insertCmd.Parameters.AddWithValue("@year", menu.Year);
|
||||
insertCmd.Parameters.AddWithValue("@cook", menu.Cook ?? (object)DBNull.Value);
|
||||
insertCmd.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,6 +343,7 @@ namespace Aberwyn.Data
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public int AddMeal(Meal meal)
|
||||
{
|
||||
using (var connection = GetConnection())
|
||||
|
||||
@@ -1,40 +1,22 @@
|
||||
# Base image for runtime
|
||||
#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
|
||||
WORKDIR /app
|
||||
EXPOSE 80
|
||||
EXPOSE 443
|
||||
|
||||
RUN mkdir -p /app/build && chmod -R 777 /app/build
|
||||
|
||||
# Leave the ports exposed to allow Unraid to configure them
|
||||
EXPOSE 80 443
|
||||
|
||||
# Image for building the project
|
||||
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
|
||||
WORKDIR /src
|
||||
|
||||
# Copy the .csproj and restore dependencies
|
||||
COPY Aberwyn/Aberwyn.csproj ./
|
||||
RUN dotnet restore
|
||||
|
||||
#COPY Aberwyn/Aberwyn.csproj ./Aberwyn/
|
||||
#WORKDIR /src/Aberwyn
|
||||
#RUN dotnet restore
|
||||
|
||||
|
||||
# Copy everything else and build the app
|
||||
COPY ["Aberwyn/Aberwyn.csproj", "Aberwyn/"]
|
||||
RUN dotnet restore "Aberwyn/Aberwyn.csproj"
|
||||
COPY . .
|
||||
RUN dotnet build Aberwyn.csproj -c Release -o /app/build/
|
||||
WORKDIR "/src/Aberwyn"
|
||||
RUN dotnet build "Aberwyn.csproj" -c Release -o /app/build
|
||||
|
||||
# Publish the app to the /app/publish folder
|
||||
FROM build AS publish
|
||||
RUN dotnet publish Aberwyn.csproj -c Release -o /app/publish
|
||||
RUN dotnet publish "Aberwyn.csproj" -c Release -o /app/publish
|
||||
|
||||
# Use the base runtime image to run the app
|
||||
FROM base AS final
|
||||
WORKDIR /app
|
||||
COPY --from=publish /app/publish .
|
||||
|
||||
# Use environment variable for ports to allow flexibility
|
||||
ENV ASPNETCORE_URLS="http://+:80"
|
||||
|
||||
# Set entry point to start the application
|
||||
ENTRYPOINT ["dotnet", "Aberwyn.dll"]
|
||||
ENTRYPOINT ["dotnet", "Aberwyn.dll"]
|
||||
@@ -15,15 +15,18 @@ namespace Aberwyn.Models
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public int DayOfWeek { get; set; }
|
||||
public int? DinnerMealId { get; set; }
|
||||
public int? BreakfastMealId { get; set; } // 👈 Lägg till denna
|
||||
public int? LunchMealId { get; set; }
|
||||
public int? DinnerMealId { get; set; }
|
||||
public string Cook { get; set; }
|
||||
public int WeekNumber { get; set; }
|
||||
public int Year { get; set; }
|
||||
public string DinnerMealName { get; set; }
|
||||
public string BreakfastMealName { get; set; } // 👈 Och denna
|
||||
public string LunchMealName { get; set; }
|
||||
public string DinnerMealName { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public class Meal
|
||||
{
|
||||
public int Id { get; set; }
|
||||
@@ -32,6 +35,7 @@ namespace Aberwyn.Models
|
||||
public string ProteinType { get; set; }
|
||||
public string CarbType { get; set; }
|
||||
public string RecipeUrl { get; set; }
|
||||
public string ImageUrl { get; set; }
|
||||
public DateTime CreatedAt { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
10
Aberwyn/Models/User.cs
Normal file
10
Aberwyn/Models/User.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace Aberwyn.Models
|
||||
{
|
||||
public class User
|
||||
{
|
||||
public int UserID { get; set; }
|
||||
public string Username { get; set; }
|
||||
public string Name { get; set; }
|
||||
}
|
||||
|
||||
}
|
||||
30
Aberwyn/Models/WeeklyMenuViewModel.cs
Normal file
30
Aberwyn/Models/WeeklyMenuViewModel.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
|
||||
namespace Aberwyn.Models
|
||||
{
|
||||
public class WeeklyMenuViewModel
|
||||
{
|
||||
public int WeekNumber { get; set; }
|
||||
public int Year { get; set; }
|
||||
|
||||
public List<WeeklyMenu> WeeklyMenus { get; set; } = new();
|
||||
public List<User> AvailableCooks { get; set; } = new();
|
||||
|
||||
public WeeklyMenu GetMealEntry(int day, string type)
|
||||
{
|
||||
int dayOfWeek = day + 1;
|
||||
|
||||
return WeeklyMenus.FirstOrDefault(m =>
|
||||
m.DayOfWeek == dayOfWeek &&
|
||||
(
|
||||
(type == "Frukost" && m.BreakfastMealId.HasValue) ||
|
||||
(type == "Lunch" && m.LunchMealId.HasValue) ||
|
||||
(type == "Middag" && m.DinnerMealId.HasValue)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,9 @@
|
||||
using Microsoft.EntityFrameworkCore; // Add this for DbContext
|
||||
using Aberwyn.Data; // Include your data namespace
|
||||
using MySql.EntityFrameworkCore.Extensions; // For MySQL support
|
||||
using System.Text;
|
||||
using System.Globalization;
|
||||
using Microsoft.AspNetCore.Localization;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
@@ -20,6 +23,14 @@ builder.Services.AddScoped<BudgetService>();
|
||||
builder.Services.AddScoped<MenuService>();
|
||||
|
||||
|
||||
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
||||
builder.Services.Configure<RequestLocalizationOptions>(options =>
|
||||
{
|
||||
var supportedCultures = new[] { new CultureInfo("sv-SE") };
|
||||
options.DefaultRequestCulture = new RequestCulture("sv-SE");
|
||||
options.SupportedCultures = supportedCultures;
|
||||
options.SupportedUICultures = supportedCultures;
|
||||
});
|
||||
var app = builder.Build();
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
|
||||
45
Aberwyn/Views/FoodMenu/MealAdmin.cshtml
Normal file
45
Aberwyn/Views/FoodMenu/MealAdmin.cshtml
Normal file
@@ -0,0 +1,45 @@
|
||||
@model List<Meal>
|
||||
@{
|
||||
ViewData["Title"] = "Alla måltider";
|
||||
}
|
||||
|
||||
<h1>Alla måltider</h1>
|
||||
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Namn</th>
|
||||
<th>Beskrivning</th>
|
||||
<th>Protein</th>
|
||||
<th>Kolhydrat</th>
|
||||
<th>Receptlänk</th>
|
||||
<th>Skapad</th>
|
||||
<th>Redigera</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var meal in Model)
|
||||
{
|
||||
<tr>
|
||||
<td>
|
||||
<a asp-controller="Meal" asp-action="View" asp-route-id="@meal.Id">@meal.Name</a>
|
||||
</td>
|
||||
<td>@meal.Description</td>
|
||||
<td>@meal.ProteinType</td>
|
||||
<td>@meal.CarbType</td>
|
||||
<td>
|
||||
@if (!string.IsNullOrWhiteSpace(meal.RecipeUrl))
|
||||
{
|
||||
<a href="@meal.RecipeUrl" target="_blank">Länk</a>
|
||||
}
|
||||
</td>
|
||||
<td>@meal.CreatedAt.ToString("yyyy-MM-dd")</td>
|
||||
<td>
|
||||
<a asp-controller="Meal" asp-action="Edit" asp-route-id="@meal.Id">Redigera</a>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<a class="btn btn-success" asp-controller="Meal" asp-action="Edit">Lägg till ny måltid</a>
|
||||
93
Aberwyn/Views/FoodMenu/Veckomeny.cshtml
Normal file
93
Aberwyn/Views/FoodMenu/Veckomeny.cshtml
Normal file
@@ -0,0 +1,93 @@
|
||||
@model WeeklyMenuViewModel
|
||||
@{
|
||||
ViewData["Title"] = "Veckomeny";
|
||||
var days = new[] { "Måndag", "Tisdag", "Onsdag", "Torsdag", "Fredag", "Lördag", "Söndag" };
|
||||
var mealTypes = new[] { "Frukost", "Lunch", "Middag" };
|
||||
}
|
||||
|
||||
<h1>Veckomeny - Vecka @Model.WeekNumber</h1>
|
||||
|
||||
<div class="week-nav">
|
||||
<a asp-action="Veckomeny" asp-route-week="@(@Model.WeekNumber - 1)">Föregående vecka</a>
|
||||
<a asp-action="Veckomeny" asp-route-week="@(@Model.WeekNumber + 1)">Nästa vecka</a>
|
||||
</div>
|
||||
|
||||
<form method="post" asp-action="SaveVeckomeny">
|
||||
<table class="menu-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Dag</th>
|
||||
@foreach (var mealType in mealTypes)
|
||||
{
|
||||
<th>@mealType</th>
|
||||
}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@for (int i = 0; i < 7; i++)
|
||||
{
|
||||
<tr>
|
||||
<td>@days[i]</td>
|
||||
@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
|
||||
};
|
||||
<td>
|
||||
<input type="text" name="Meal[@i][@mealType]"
|
||||
value="@mealName"
|
||||
placeholder="Lägg till måltid..."
|
||||
class="meal-input" data-day="@i" data-type="@mealType" list="meals-list" />
|
||||
<select name="Cook[@i][@mealType]">
|
||||
<option value="">Vem lagar?</option>
|
||||
@foreach (var user in Model.AvailableCooks)
|
||||
{
|
||||
if (entry?.Cook == user.Username)
|
||||
{
|
||||
<option value="@user.Username" selected>@user.Name</option>
|
||||
}
|
||||
else
|
||||
{
|
||||
<option value="@user.Username">@user.Name</option>
|
||||
}
|
||||
}
|
||||
</select>
|
||||
</td>
|
||||
}
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
<button type="submit">Spara veckomeny</button>
|
||||
</form>
|
||||
|
||||
<datalist id="meals-list"></datalist>
|
||||
|
||||
@section Scripts {
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||
<script>
|
||||
$(function() {
|
||||
$('.meal-input').on('focus input', function() {
|
||||
const input = $(this);
|
||||
const term = input.val();
|
||||
input.attr('list', 'meals-list'); // tvinga list-id
|
||||
$.getJSON('/FoodMenu/SearchMeals', { term: term }, function(data) {
|
||||
const list = $('#meals-list');
|
||||
list.empty();
|
||||
data.forEach(name => {
|
||||
list.append(`<option value="${name}">`);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function showMealInfo(name, cook) {
|
||||
alert(`Måltid: ${name}\nLagas av: ${cook}`);
|
||||
}
|
||||
</script>
|
||||
}
|
||||
@@ -1,127 +1,21 @@
|
||||
@{
|
||||
ViewData["Title"] = "Home Page";
|
||||
ViewData["Title"] = "Welcome to Aberwyn!";
|
||||
}
|
||||
|
||||
<div class="text-center">
|
||||
|
||||
<html>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
|
||||
<link rel="alternate" type="application/rss+xml" title="zcz RSS" href="/rss.xml">
|
||||
|
||||
<style type="text/css">
|
||||
|
||||
body {
|
||||
|
||||
scrollbar-face-color: #999999;
|
||||
|
||||
scrollbar-highlight-color: #999999;
|
||||
|
||||
scrollbar-shadow-color: #202020;
|
||||
|
||||
scrollbar-3dlight-color: ##666666;
|
||||
|
||||
scrollbar-arrow-color: #383838;
|
||||
|
||||
scrollbar-track-color: #202020;
|
||||
|
||||
scrollbar-darkshadow-color: #212121;
|
||||
|
||||
Background-position: 50% 0%;
|
||||
|
||||
background-Color: #1F2C3C;
|
||||
|
||||
}
|
||||
|
||||
.tab { border-collapse: collapse; }
|
||||
|
||||
.Main { background-image: url(/images/bg.gif); background-repeat: repeat-y; }
|
||||
|
||||
.Navi { background-image: url(/images/navi.gif); background-repeat: repeat-y; }
|
||||
|
||||
.footer { background-image: url(/images/footer.gif); background-repeat: repeat-y; }
|
||||
|
||||
</style>
|
||||
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>@ViewData["Title"]</title>
|
||||
<link rel="stylesheet" href="~/css/site.css">
|
||||
</head>
|
||||
|
||||
<body link="#6165A3" vlink="#6F76CC" alink="#66ACFF">
|
||||
|
||||
<table border="0" width="800" align="Center">
|
||||
|
||||
<td>
|
||||
|
||||
<table cellpadding="0" cellspacing="0" border="0" align="Center" bordercolor="#111111">
|
||||
|
||||
<td valign="Top" width=799>
|
||||
|
||||
</td>
|
||||
|
||||
</table>
|
||||
|
||||
<table border="0" height="100%" cellpadding="0" width="100%" cellspacing="1" align="Center" bordercolor="#111111" class="Main">
|
||||
|
||||
<td valign="Top" width=100 height="120" class=Navi>
|
||||
|
||||
<?php include "navi.php"; ?>
|
||||
|
||||
</td>
|
||||
|
||||
<td valign="Top" rowspan="2"><br>
|
||||
|
||||
<?php
|
||||
|
||||
if (isset($page)) {
|
||||
|
||||
$pagetoshow = "$page.php";
|
||||
|
||||
if (file_exists($pagetoshow)) {
|
||||
|
||||
include "$pagetoshow";
|
||||
|
||||
} else {
|
||||
|
||||
include "error.php";
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!isset($page)) { include "main.php"; }
|
||||
|
||||
?>
|
||||
|
||||
</td>
|
||||
|
||||
<tr>
|
||||
|
||||
<td valign="Top" width=100 class=Navi>
|
||||
|
||||
<?php // include "login.php"; ?>
|
||||
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
||||
<table border="0" height="100%" cellpadding="10" width="100%" cellspacing="1" align="Center" bordercolor="#111111" class="footer">
|
||||
|
||||
<img src="/images/border.gif">
|
||||
|
||||
<td width="100%" valign="Center">
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
</table>
|
||||
|
||||
</td>
|
||||
|
||||
</table>
|
||||
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>Welcome to Aberwyn!</h1>
|
||||
<p>Your home for managing all your budget and meal planning needs.</p>
|
||||
<p>We’re glad to have you here. Get started by exploring our features.</p>
|
||||
<a href="/Home/About" class="button">Learn More</a>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
@model Aberwyn.Models.MenuViewModel
|
||||
|
||||
@{
|
||||
Layout = "_Layout";
|
||||
// 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'
|
||||
}
|
||||
|
||||
<!DOCTYPE html>
|
||||
@@ -20,14 +22,9 @@
|
||||
<h1 class="page-title">Meal Menu Overview</h1>
|
||||
|
||||
<div class="date-picker">
|
||||
<button type="button" class="date-btn" ng-click="goToPreviousWeek()">Previous Week</button>
|
||||
<span class="week-info">Week {{ selectedWeek }} - {{ selectedYear }}</span>
|
||||
<button type="button" class="date-btn" ng-click="goToNextWeek()">Next Week</button>
|
||||
</div>
|
||||
|
||||
<div class="mode-toggle">
|
||||
<button ng-click="toggleEditMode()" ng-show="!isEditing" class="mode-btn">Edit</button>
|
||||
<button ng-click="toggleEditMode()" ng-show="isEditing" class="mode-btn">View</button>
|
||||
<button type="button" class="date-btn" ng-click="goToPreviousWeek()">Föregående vecka</button>
|
||||
<span class="week-info">Vecka {{ selectedWeek }} - {{ selectedYear }}</span>
|
||||
<button type="button" class="date-btn" ng-click="goToNextWeek()">Nästa vecka</button>
|
||||
</div>
|
||||
|
||||
<div class="meal-menu-container">
|
||||
@@ -37,62 +34,21 @@
|
||||
<div class="meal-info" ng-if="!isEditing">
|
||||
<div ng-if="menu[day]">
|
||||
<div ng-if="menu[day].breakfastMealName">
|
||||
<span><strong>Breakfast:</strong> {{ menu[day].breakfastMealName }}</span>
|
||||
<span><strong>Frukost:</strong> {{ menu[day].breakfastMealName }}</span>
|
||||
</div>
|
||||
<div ng-if="menu[day].lunchMealName">
|
||||
<span><strong>Lunch:</strong> {{ menu[day].lunchMealName }}</span>
|
||||
</div>
|
||||
<div ng-if="menu[day].dinnerMealName">
|
||||
<span><strong>Dinner:</strong> {{ menu[day].dinnerMealName }}</span>
|
||||
<span><strong>Middag:</strong> {{ menu[day].dinnerMealName }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-if="!menu[day]">
|
||||
<span class="not-assigned">Not Assigned</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="meal-edit" ng-if="isEditing">
|
||||
<div>
|
||||
<strong>Breakfast:</strong>
|
||||
<select ng-model="menu[day].breakfastMealId" ng-change="handleMealSelection(day, 'breakfast')"
|
||||
ng-options="meal.id as meal.name for meal in meals">
|
||||
<option value="">Select Meal</option>
|
||||
<option value="new">New Meal</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<strong>Lunch:</strong>
|
||||
<select ng-model="menu[day].lunchMealId" ng-change="handleMealSelection(day, 'lunch')"
|
||||
ng-options="meal.id as meal.name for meal in meals">
|
||||
<option value="">Select Meal</option>
|
||||
<option value="new">New Meal</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<strong>Dinner:</strong>
|
||||
<select ng-model="menu[day].dinnerMealId" ng-change="handleMealSelection(day, 'dinner')"
|
||||
ng-options="meal.id as meal.name for meal in meals">
|
||||
<option value="">Select Meal</option>
|
||||
<option value="new">New Meal</option>
|
||||
</select>
|
||||
<span class="not-assigned">Inte bestämd</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button ng-if="isEditing" ng-click="saveMenu()" class="save-btn">Save Menu</button>
|
||||
</div>
|
||||
|
||||
<div class="new-meal-form" ng-if="isEditing">
|
||||
<h3>Add a New Meal</h3>
|
||||
<input type="text" placeholder="Meal Name" ng-model="newMeal.name">
|
||||
<input type="text" placeholder="Description" ng-model="newMeal.description">
|
||||
<input type="text" placeholder="Protein Type" ng-model="newMeal.proteinType">
|
||||
<input type="text" placeholder="Carb Type" ng-model="newMeal.carbType">
|
||||
<input type="text" placeholder="Recipe URL" ng-model="newMeal.recipeUrl">
|
||||
<button ng-click="saveNewMeal()">Save Meal</button>
|
||||
<button ng-click="cancelNewMeal()">Cancel</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
77
Aberwyn/Views/Meal/Meal.cshtml
Normal file
77
Aberwyn/Views/Meal/Meal.cshtml
Normal file
@@ -0,0 +1,77 @@
|
||||
@model Aberwyn.Models.Meal
|
||||
@{
|
||||
ViewData["Title"] = Model.Id == 0 ? "Ny måltid" : Model.Name;
|
||||
var isNew = Model.Id == 0;
|
||||
}
|
||||
|
||||
<div class="meal-details">
|
||||
<h1>@(isNew ? "Skapa ny måltid" : Model.Name)</h1>
|
||||
|
||||
<form asp-action="SaveMeal" method="post" enctype="multipart/form-data">
|
||||
@if (!isNew)
|
||||
{
|
||||
<input type="hidden" name="Id" value="@Model.Id" />
|
||||
}
|
||||
|
||||
<div>
|
||||
<label for="Name">Namn</label>
|
||||
<input type="text" name="Name" value="@Model.Name" required />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="Description">Beskrivning</label>
|
||||
<textarea name="Description">@Model.Description</textarea>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="ProteinType">Protein</label>
|
||||
<input type="text" name="ProteinType" value="@Model.ProteinType" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="CarbType">Kolhydrat</label>
|
||||
<input type="text" name="CarbType" value="@Model.CarbType" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="RecipeUrl">Receptlänk</label>
|
||||
<input type="url" name="RecipeUrl" value="@Model.RecipeUrl" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="ImageFile">Bild</label>
|
||||
<input type="file" name="ImageFile" />
|
||||
</div>
|
||||
|
||||
<button type="submit">Spara</button>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.meal-details {
|
||||
max-width: 600px;
|
||||
margin: 2rem auto;
|
||||
background: #f9f9f9;
|
||||
padding: 2rem;
|
||||
border-radius: 8px;
|
||||
}
|
||||
.meal-details label {
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
.meal-details input[type=text],
|
||||
.meal-details input[type=url],
|
||||
.meal-details textarea {
|
||||
width: 100%;
|
||||
padding: 0.5rem;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #ccc;
|
||||
margin-top: 0.25rem;
|
||||
}
|
||||
.meal-details button {
|
||||
margin-top: 1rem;
|
||||
margin-right: 1rem;
|
||||
}
|
||||
</style>
|
||||
90
Aberwyn/Views/Meal/View.cshtml
Normal file
90
Aberwyn/Views/Meal/View.cshtml
Normal file
@@ -0,0 +1,90 @@
|
||||
@model Aberwyn.Models.Meal
|
||||
@{
|
||||
ViewData["Title"] = Model.Name;
|
||||
}
|
||||
|
||||
<div class="meal-container">
|
||||
<h1>@Model.Name</h1>
|
||||
|
||||
@if (!string.IsNullOrEmpty(Model.ImageUrl))
|
||||
{
|
||||
<img src="@Model.ImageUrl" alt="@Model.Name" class="meal-image" />
|
||||
}
|
||||
|
||||
@if (!string.IsNullOrEmpty(Model.Description))
|
||||
{
|
||||
<p class="description">@Model.Description</p>
|
||||
}
|
||||
|
||||
<div class="buttons">
|
||||
<button onclick="toggleRecipe()">Visa Recept</button>
|
||||
<a class="edit-button" asp-controller="Meal" asp-action="Edit" asp-route-id="@Model.Id">Redigera</a>
|
||||
</div>
|
||||
|
||||
<div id="recipe-section" style="display:none;">
|
||||
<h2>Så här gör du</h2>
|
||||
<p>(Tillagningsinstruktioner kommer snart...)</p>
|
||||
|
||||
@if (!string.IsNullOrEmpty(Model.RecipeUrl))
|
||||
{
|
||||
<p><a href="@Model.RecipeUrl" target="_blank">Öppna fullständigt recept</a></p>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function toggleRecipe() {
|
||||
var section = document.getElementById('recipe-section');
|
||||
if (section.style.display === 'none') {
|
||||
section.style.display = 'block';
|
||||
} else {
|
||||
section.style.display = 'none';
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.meal-container {
|
||||
max-width: 700px;
|
||||
margin: 2rem auto;
|
||||
background: #fff;
|
||||
padding: 2rem;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
|
||||
text-align: center;
|
||||
}
|
||||
.meal-container h1 {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
.meal-container .meal-image {
|
||||
width: 100%;
|
||||
max-height: 400px;
|
||||
object-fit: cover;
|
||||
border-radius: 10px;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
.meal-container .description {
|
||||
font-style: italic;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
.meal-container .buttons {
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
.meal-container .buttons button, .meal-container .buttons .edit-button {
|
||||
background-color: #6a0dad;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 0.7rem 1.5rem;
|
||||
border-radius: 5px;
|
||||
margin: 0.5rem;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
.meal-container .buttons .edit-button {
|
||||
display: inline-block;
|
||||
}
|
||||
.meal-container a {
|
||||
color: #6a0dad;
|
||||
text-decoration: underline;
|
||||
}
|
||||
</style>
|
||||
@@ -37,17 +37,30 @@
|
||||
<i class="fas fa-building"></i> RealEstate
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-section-title">Måltider</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" asp-area="" asp-controller="Home" asp-action="Menu">
|
||||
<i class="fas fa-utensils"></i> Menu
|
||||
<i class="fas fa-utensils"></i> Menyöversikt
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" asp-area="" asp-controller="FoodMenu" asp-action="Veckomeny">
|
||||
<i class="fas fa-calendar-week"></i> Veckomeny
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" asp-area="" asp-controller="FoodMenu" asp-action="MealAdmin">
|
||||
<i class="fas fa-list"></i> Matlista
|
||||
</a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</aside>
|
||||
|
||||
<main role="main" class="main-content">
|
||||
@RenderBody()
|
||||
@RenderSection("Scripts", required: false)
|
||||
</main>
|
||||
|
||||
<!-- Right Sidebar with budget data from the RightSidebarViewComponent -->
|
||||
@@ -57,5 +70,6 @@
|
||||
</div>
|
||||
|
||||
<script src="~/js/site.js" asp-append-version="true"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -8,6 +8,6 @@
|
||||
"AllowedHosts": "*",
|
||||
"ConnectionStrings": {
|
||||
"DefaultConnection": "Server=192.168.1.108;Database=Nevyn;Uid=root;Pwd=3edc4RFV;",
|
||||
"ProductionConnection": "Server=172.18.0.2;Database=Nevyn;Uid=root;Pwd=3edc4RFV;"
|
||||
"ProductionConnection": "Server=192.168.1.108;Database=Nevyn;Uid=root;Pwd=3edc4RFV;"
|
||||
}
|
||||
}
|
||||
|
||||
15
Aberwyn/wwwroot/css/menu-style.css
Normal file
15
Aberwyn/wwwroot/css/menu-style.css
Normal file
@@ -0,0 +1,15 @@
|
||||
|
||||
.menu-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-top: 1em;
|
||||
}
|
||||
.menu-table th, .menu-table td {
|
||||
border: 1px solid #444;
|
||||
padding: 0.5em;
|
||||
}
|
||||
.week-nav {
|
||||
margin-bottom: 1em;
|
||||
display: flex;
|
||||
gap: 1em;
|
||||
}
|
||||
@@ -224,3 +224,4 @@ body {
|
||||
.date-picker-dropdown select:hover {
|
||||
background-color: #555;
|
||||
}
|
||||
|
||||
|
||||
10
Aberwyn/wwwroot/js/meal-menu.js
Normal file
10
Aberwyn/wwwroot/js/meal-menu.js
Normal file
@@ -0,0 +1,10 @@
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
document.querySelectorAll(".meal-cell").forEach(cell => {
|
||||
cell.addEventListener("click", function () {
|
||||
const name = this.getAttribute("data-name");
|
||||
const cook = this.getAttribute("data-cook");
|
||||
alert(`Måltid: ${name}\nLagas av: ${cook}`);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,4 +1,4 @@
|
||||
angular.module('mealMenuApp', [])
|
||||
angular.module('mealMenuApp', [])
|
||||
.controller('MealMenuController', function ($scope, $http) {
|
||||
$scope.isEditing = false;
|
||||
$scope.toggleEditMode = function () {
|
||||
@@ -15,7 +15,7 @@ angular.module('mealMenuApp', [])
|
||||
const today = new Date();
|
||||
$scope.selectedWeek = getWeek(today);
|
||||
$scope.selectedYear = today.getFullYear();
|
||||
$scope.daysOfWeek = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"];
|
||||
$scope.daysOfWeek = ["Måndag", "Tisdag", "Onsdag", "Torsdag", "Fredag", "Lördag", "Söndag"];
|
||||
|
||||
$scope.loadMeals = function () {
|
||||
$http.get('/api/mealMenuApi/getMeals')
|
||||
@@ -29,6 +29,8 @@ angular.module('mealMenuApp', [])
|
||||
$http.get('/api/mealMenuApi/menu', {
|
||||
params: { weekNumber: $scope.selectedWeek, year: $scope.selectedYear }
|
||||
}).then(response => {
|
||||
console.log("Veckomenydata:", response.data); // ✅ logga ut
|
||||
|
||||
$scope.menu = {};
|
||||
response.data.forEach(item => {
|
||||
const dayOfWeek = $scope.daysOfWeek[item.dayOfWeek - 1];
|
||||
|
||||
BIN
Aberwyn/wwwroot/uploads/fc8aff8c-4bef-45a8-9e40-7b78f76f04e8.png
Normal file
BIN
Aberwyn/wwwroot/uploads/fc8aff8c-4bef-45a8-9e40-7b78f76f04e8.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 30 KiB |
Reference in New Issue
Block a user