diff --git a/Aberwyn/Controllers/BudgetController.cs b/Aberwyn/Controllers/BudgetController.cs index e6cbdab..35cb859 100644 --- a/Aberwyn/Controllers/BudgetController.cs +++ b/Aberwyn/Controllers/BudgetController.cs @@ -3,13 +3,23 @@ using Microsoft.AspNetCore.Mvc; namespace Aberwyn.Controllers { + [Authorize(Roles = "Budget")] public class BudgetController : Controller { - [Authorize(Roles = "Budget")] - public IActionResult Index() + [Route("budget/{year:int}/{month:int}")] + public IActionResult Index(int year, int month) { - ViewData["HideSidebar"] = true; + ViewBag.Year = year; + ViewBag.Month = month; return View(); } + + // För fallback när ingen månad/år anges + [Route("budget")] + public IActionResult Index() + { + var now = DateTime.Now; + return RedirectToAction("Index", new { year = now.Year, month = now.Month }); + } } -} \ No newline at end of file +} diff --git a/Aberwyn/Data/MenuService.cs b/Aberwyn/Data/MenuService.cs index c5d24de..3c91cfc 100644 --- a/Aberwyn/Data/MenuService.cs +++ b/Aberwyn/Data/MenuService.cs @@ -344,7 +344,6 @@ public List GetWeeklyMenu(int weekNumber, int year) int week = ISOWeek.GetWeekOfYear(date); int year = date.Year; - // Gör om till ISO 8601: Måndag = 1, Söndag = 7 int dayOfWeek = (int)date.DayOfWeek; if (dayOfWeek == 0) dayOfWeek = 7; @@ -361,20 +360,30 @@ public List GetWeeklyMenu(int weekNumber, int year) var allMeals = _context.Meals .Where(m => mealIds.Contains(m.Id)) - .ToDictionary(m => m.Id, m => m.Name); + .ToDictionary(m => m.Id); - if (menu.BreakfastMealId.HasValue && allMeals.TryGetValue(menu.BreakfastMealId.Value, out var breakfast)) - menu.BreakfastMealName = breakfast; - if (menu.LunchMealId.HasValue && allMeals.TryGetValue(menu.LunchMealId.Value, out var lunch)) - menu.LunchMealName = lunch; - if (menu.DinnerMealId.HasValue && allMeals.TryGetValue(menu.DinnerMealId.Value, out var dinner)) - menu.DinnerMealName = dinner; + if (menu.BreakfastMealId is int bId && allMeals.TryGetValue(bId, out var breakfast)) + { + menu.BreakfastMealName = breakfast.Name; + menu.BreakfastThumbnail = breakfast.ThumbnailData; + } + + if (menu.LunchMealId is int lId && allMeals.TryGetValue(lId, out var lunch)) + { + menu.LunchMealName = lunch.Name; + menu.LunchThumbnail = lunch.ThumbnailData; + } + + if (menu.DinnerMealId is int dId && allMeals.TryGetValue(dId, out var dinner)) + { + menu.DinnerMealName = dinner.Name; + menu.DinnerThumbnail = dinner.ThumbnailData; + } } return menu; } - public List GetMenuEntriesByDateRange(DateTime startDate, DateTime endDate) { var results = new List(); diff --git a/Aberwyn/Models/MenuViewModel.cs b/Aberwyn/Models/MenuViewModel.cs index 449763e..34f452e 100644 --- a/Aberwyn/Models/MenuViewModel.cs +++ b/Aberwyn/Models/MenuViewModel.cs @@ -43,6 +43,9 @@ public class WeeklyMenu public int WeekNumber { get; set; } public int Year { get; set; } public DateTime CreatedAt { get; set; } + [NotMapped] public byte[]? BreakfastThumbnail { get; set; } + [NotMapped] public byte[]? LunchThumbnail { get; set; } + [NotMapped] public byte[]? DinnerThumbnail { get; set; } [NotMapped] public string? BreakfastMealName { get; set; } [NotMapped] public string? LunchMealName { get; set; } diff --git a/Aberwyn/Views/Budget/Index.cshtml b/Aberwyn/Views/Budget/Index.cshtml index 788539d..beb37df 100644 --- a/Aberwyn/Views/Budget/Index.cshtml +++ b/Aberwyn/Views/Budget/Index.cshtml @@ -4,6 +4,7 @@ @{ ViewData["Title"] = "Budget"; } +
@@ -93,7 +94,7 @@ on-category-drop="handleCategoryDrop(data, targetCategory)">
-
{{ cat.name }}
+
{{ cat.name }}
@@ -129,11 +130,10 @@ ng-show="cat.editing" style="opacity: 0.5; padding-right: 6px; cursor: grab;"> - - {{ item.name }} - - - {{ item.amount | number:0 }} + + {{ item.name }} + + {{ item.amount | number:0 }}
@@ -231,5 +231,9 @@ + \ No newline at end of file diff --git a/Aberwyn/Views/Home/Index.cshtml b/Aberwyn/Views/Home/Index.cshtml index 8578759..be36cc8 100644 --- a/Aberwyn/Views/Home/Index.cshtml +++ b/Aberwyn/Views/Home/Index.cshtml @@ -18,27 +18,87 @@ @if (Model != null) {
+ @if (!string.IsNullOrWhiteSpace(Model.BreakfastMealName)) { -

Frukost: @Model.BreakfastMealName

+
+ @if (Model.BreakfastThumbnail != null) + { + var b64 = Convert.ToBase64String(Model.BreakfastThumbnail); + + } +

Frukost: @Model.BreakfastMealName

+
} + @if (!string.IsNullOrWhiteSpace(Model.LunchMealName)) { -

Lunch: @Model.LunchMealName

+
+ @if (Model.LunchThumbnail != null) + { + var b64 = Convert.ToBase64String(Model.LunchThumbnail); + + } +

Lunch: @Model.LunchMealName

+
} + @if (!string.IsNullOrWhiteSpace(Model.DinnerMealName)) { -

Middag: @Model.DinnerMealName

+
+ @if (Model.DinnerThumbnail != null) + { + var b64 = Convert.ToBase64String(Model.DinnerThumbnail); + + } +

Middag: @Model.DinnerMealName

+
} @if (ViewBag.RestaurantIsOpen as bool? == true) { -

Pizzerian är öppen!

Klicka här för att Beställa pizza +

Pizzerian är öppen!

+ Klicka här för att Beställa pizza } +
+ + } else {

Ingen meny är inlagd för denna dag.

} - Visa hela veckomenyn
+ + diff --git a/Aberwyn/wwwroot/css/Welcome.css b/Aberwyn/wwwroot/css/Welcome.css index 468bb4a..1f8881d 100644 --- a/Aberwyn/wwwroot/css/Welcome.css +++ b/Aberwyn/wwwroot/css/Welcome.css @@ -80,3 +80,80 @@ background: #2563eb; transform: translateY(-2px); } +.thumb-button { + border: none; + background: none; + padding: 0; + cursor: pointer; +} + +.meal-line { + display: flex; + align-items: center; + gap: 12px; + margin-bottom: 10px; +} + +.meal-thumb { + width: 48px; + height: 48px; + object-fit: cover; + border-radius: 6px; + box-shadow: 0 2px 4px rgba(0,0,0,0.1); +} + +.lightbox-overlay { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0,0,0,0.8); + display: flex; + align-items: center; + justify-content: center; + z-index: 10000; + padding: 20px; +} + +.lightbox-content { + position: relative; + max-width: 90%; + max-height: 90%; + display: flex; + flex-direction: column; + align-items: center; +} + +.lightbox-image { + max-width: 100%; + max-height: 80vh; + border-radius: 8px; + box-shadow: 0 4px 16px rgba(0,0,0,0.5); +} + +.lightbox-caption { + color: white; + margin-top: 10px; + font-size: 16px; + text-align: center; +} + +.close-lightbox { + position: absolute; + top: -10px; + right: -10px; + background: #fff; + color: #333; + border: none; + border-radius: 50%; + font-size: 20px; + width: 32px; + height: 32px; + cursor: pointer; + box-shadow: 0 2px 6px rgba(0,0,0,0.3); +} + +.no-scroll { + overflow: hidden; +} diff --git a/Aberwyn/wwwroot/css/budget.css b/Aberwyn/wwwroot/css/budget.css index 0201bdc..9d74fbd 100644 --- a/Aberwyn/wwwroot/css/budget.css +++ b/Aberwyn/wwwroot/css/budget.css @@ -1,18 +1,23 @@ :root { - --text-main: #1E293B; - --text-sub: #64748B; - --bg-main: #f9fafb; - --bg-card: #f1f5f9; - --border-color: #e5e7eb; - --card-income: #f97316; + --text-main: #1F2937; /* Mörkblågrå – tydlig men mjuk */ + --text-sub: #64748B; /* Sekundär gråblå */ + --bg-main: #1F2C3C; /* SID-bakgrund */ + --bg-card: #dbe3ec; + --bg-card-summary: #d6dde6; + --border-color: #cbd5e1; /* Ljus kant men inte skarp */ + --item-divider: rgba(0, 0, 0, 0.05); /* ljus standard */ + + --card-income: #fb923c; --card-expense: #ef4444; --card-savings: #facc15; - --card-leftover: #86efac; + --card-leftover: #4ade80; --btn-edit: #3b82f6; --btn-check: #10b981; --btn-delete: #ef4444; } + + body { background-color: var(--bg-main); color: var(--text-main); @@ -105,6 +110,7 @@ body { height: 350px; border: 1px solid var(--border-color); border-radius: 12px; + color: var(--text-main); background-color: var(--bg-card); box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05); overflow: hidden; @@ -134,6 +140,7 @@ body { border-top: 1px solid var(--border-color); border-radius: 0 0 12px 12px; flex-shrink: 0; + background: var(--bg-card-summary); } .card-header { @@ -521,7 +528,10 @@ color: var(--btn-check); padding: 8px 12px; border-radius: 8px; box-shadow: 0 1px 3px rgba(0,0,0,0.04); + text-shadow: 0 1px 2px rgba(0, 0, 0, 0.15); min-width: 220px; + background-color: var(--bg-card); + color: var(--text-main); } .budget-summary-box h3, @@ -601,7 +611,18 @@ canvas { height: auto; } + +body.dark-mode { + --item-divider: rgba(255, 255, 255, 0.05); /* för mörk bakgrund */ +} + +.item-row:not(.total-row) { + border-bottom: 1px solid var(--item-divider); + padding-bottom: 4px; + margin-bottom: 4px; +} @media (min-width: 769px) { + .budget-overview-row { display: grid; grid-template-columns: 1fr 1fr; @@ -634,10 +655,51 @@ canvas { max-width: 100%; height: auto; } + .item-row { + display: flex; + align-items: center; + justify-content: space-between; + gap: 8px; + padding: 4px 8px; + border-bottom: 1px solid var(--border-color); + } + + .item-label { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + max-width: 100%; + display: inline-block; + } + + .amount { + flex-shrink: 0; + white-space: nowrap; + font-weight: bold; + } + } @media (max-width: 768px) { + .item-label { + white-space: normal; + overflow-wrap: break-word; + word-break: break-word; + flex: 1 1 auto; + max-width: 100%; + + } + + .amount { + white-space: nowrap; + text-align: right; + flex-shrink: 0; + } + + .budget-grid { + grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); + } .budget-overview-row { display: flex; flex-direction: column; @@ -662,6 +724,8 @@ canvas { width: 100%; text-align: center; padding-bottom: 10px; + color: #1E293B; /* djupare textfärg */ + font-weight: 600; } .chart-area canvas { diff --git a/Aberwyn/wwwroot/js/budget.js b/Aberwyn/wwwroot/js/budget.js index e1c0aef..ec3e44f 100644 --- a/Aberwyn/wwwroot/js/budget.js +++ b/Aberwyn/wwwroot/js/budget.js @@ -7,13 +7,17 @@ app.controller('BudgetController', function ($scope, $http) { $scope.menuOpen = false; $scope.chartMode = "pie"; - const today = new Date(); - $scope.selectedYear = today.getFullYear(); - $scope.selectedMonth = today.getMonth() + 1; - $scope.tempMonth = $scope.monthNames?.[today.getMonth()] || ""; - $scope.tempYear = $scope.selectedYear; - $scope.monthNames = ["Januari", "Februari", "Mars", "April", "Maj", "Juni", "Juli", "Augusti", "September", "Oktober", "November", "December"]; + $scope.getMonthName = function (month) { + return $scope.monthNames[month - 1] || ""; + }; + + $scope.selectedYear = window.initialYear || new Date().getFullYear(); + $scope.selectedMonth = window.initialMonth || new Date().getMonth() + 1; + + $scope.tempMonth = $scope.monthNames[$scope.selectedMonth - 1]; + $scope.tempYear = $scope.selectedYear; + $scope.selectedMonthName = $scope.getMonthName($scope.selectedMonth); $scope.getMonthName = function (month) { return $scope.monthNames[month - 1] || ""; @@ -42,6 +46,17 @@ app.controller('BudgetController', function ($scope, $http) { }; $scope.menuVisible = true; }; + $scope.updateMonthAndUrl = function () { + const year = $scope.selectedYear; + const month = $scope.selectedMonth.toString(); + const newUrl = `/budget/${year}/${month}`; + window.history.replaceState(null, '', newUrl); // Uppdaterar URL utan reload + $scope.selectedMonthName = $scope.getMonthName($scope.selectedMonth); + $scope.tempMonth = $scope.selectedMonthName; + $scope.tempYear = $scope.selectedYear; + $scope.loadBudget(); + }; + $scope.setItemType = function (item, type) { if (type === 'expense') { @@ -307,12 +322,12 @@ app.controller('BudgetController', function ($scope, $http) { if (monthIndex >= 0 && $scope.tempYear) { $scope.selectedMonth = monthIndex + 1; $scope.selectedYear = parseInt($scope.tempYear); - $scope.selectedMonthName = $scope.getMonthName($scope.selectedMonth); + $scope.updateMonthAndUrl(); $scope.showMonthPicker = false; - $scope.loadBudget(); } }; + $scope.previousMonth = function () { if ($scope.selectedMonth === 1) { $scope.selectedMonth = 12; @@ -320,12 +335,10 @@ app.controller('BudgetController', function ($scope, $http) { } else { $scope.selectedMonth--; } - $scope.tempMonth = $scope.getMonthName($scope.selectedMonth); - $scope.tempYear = $scope.selectedYear; - $scope.selectedMonthName = $scope.getMonthName($scope.selectedMonth); - $scope.loadBudget(); + $scope.updateMonthAndUrl(); }; + $scope.nextMonth = function () { if ($scope.selectedMonth === 12) { $scope.selectedMonth = 1; @@ -333,12 +346,10 @@ app.controller('BudgetController', function ($scope, $http) { } else { $scope.selectedMonth++; } - $scope.tempMonth = $scope.getMonthName($scope.selectedMonth); - $scope.tempYear = $scope.selectedYear; - $scope.selectedMonthName = $scope.getMonthName($scope.selectedMonth); - $scope.loadBudget(); + $scope.updateMonthAndUrl(); }; + $scope.handleCategoryDrop = function (data, targetCategory) { if (data.type !== 'category') return; // ⛔ stoppa om det är ett item-drag