This commit is contained in:
@@ -17,13 +17,155 @@ namespace Aberwyn.Controllers
|
|||||||
{
|
{
|
||||||
private readonly IConfiguration _configuration;
|
private readonly IConfiguration _configuration;
|
||||||
private readonly IHostEnvironment _env;
|
private readonly IHostEnvironment _env;
|
||||||
|
private readonly MenuService _menuService;
|
||||||
|
private readonly ApplicationDbContext _context;
|
||||||
|
|
||||||
public FoodMenuController(IConfiguration configuration, IHostEnvironment env)
|
public FoodMenuController(MenuService menuService, IConfiguration configuration, IHostEnvironment env, ApplicationDbContext context)
|
||||||
{
|
{
|
||||||
|
_menuService = menuService;
|
||||||
_configuration = configuration;
|
_configuration = configuration;
|
||||||
_env = env;
|
_env = env;
|
||||||
|
_context = context;
|
||||||
}
|
}
|
||||||
[Authorize(Roles = "Budget")]
|
|
||||||
|
[HttpGet]
|
||||||
|
public IActionResult PizzaOrder()
|
||||||
|
{
|
||||||
|
var pizzas = _menuService.GetMealsByCategory("Pizza");
|
||||||
|
ViewBag.Pizzas = pizzas;
|
||||||
|
|
||||||
|
int? lastId = HttpContext.Session.GetInt32("LastPizzaOrderId");
|
||||||
|
if (lastId.HasValue)
|
||||||
|
{
|
||||||
|
var previousOrder = _context.PizzaOrders.FirstOrDefault(o => o.Id == lastId.Value);
|
||||||
|
if (previousOrder != null)
|
||||||
|
{
|
||||||
|
ViewBag.PreviousOrder = previousOrder;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return View();
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
public IActionResult EditPizzaOrder(int id)
|
||||||
|
{
|
||||||
|
var order = _context.PizzaOrders.FirstOrDefault(o => o.Id == id);
|
||||||
|
if (order == null)
|
||||||
|
{
|
||||||
|
return RedirectToAction("PizzaOrder");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sätt session så vi vet att det är en uppdatering
|
||||||
|
HttpContext.Session.SetInt32("LastPizzaOrderId", order.Id);
|
||||||
|
|
||||||
|
// Visa formuläret
|
||||||
|
TempData["ForceShowForm"] = "true";
|
||||||
|
|
||||||
|
return RedirectToAction("PizzaOrder");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
public IActionResult ClearPizzaSession()
|
||||||
|
{
|
||||||
|
HttpContext.Session.Remove("LastPizzaOrderId");
|
||||||
|
return RedirectToAction("PizzaOrder");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
public IActionResult PizzaOrder(string customerName, string pizzaName, string ingredients, int? orderId)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(customerName) || string.IsNullOrWhiteSpace(pizzaName))
|
||||||
|
{
|
||||||
|
TempData["Error"] = "Fyll i både namn och pizza!";
|
||||||
|
return RedirectToAction("PizzaOrder");
|
||||||
|
}
|
||||||
|
|
||||||
|
int? lastId = orderId ?? HttpContext.Session.GetInt32("LastPizzaOrderId");
|
||||||
|
PizzaOrder order;
|
||||||
|
|
||||||
|
if (lastId.HasValue)
|
||||||
|
{
|
||||||
|
// Uppdatera befintlig order
|
||||||
|
order = _context.PizzaOrders.FirstOrDefault(o => o.Id == lastId.Value);
|
||||||
|
if (order != null)
|
||||||
|
{
|
||||||
|
order.CustomerName = customerName.Trim();
|
||||||
|
order.PizzaName = pizzaName.Trim();
|
||||||
|
order.IngredientsJson = ingredients;
|
||||||
|
order.Status = "Ej bekräftad"; // återställ status om du vill
|
||||||
|
_context.SaveChanges();
|
||||||
|
|
||||||
|
TempData["Success"] = $"Din beställning har uppdaterats!";
|
||||||
|
return RedirectToAction("PizzaOrder");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Annars skapa ny
|
||||||
|
order = new PizzaOrder
|
||||||
|
{
|
||||||
|
CustomerName = customerName.Trim(),
|
||||||
|
PizzaName = pizzaName.Trim(),
|
||||||
|
IngredientsJson = ingredients,
|
||||||
|
Status = "Ej bekräftad",
|
||||||
|
OrderedAt = DateTime.Now
|
||||||
|
};
|
||||||
|
|
||||||
|
_context.PizzaOrders.Add(order);
|
||||||
|
_context.SaveChanges();
|
||||||
|
TempData["ForceShowForm"] = "true";
|
||||||
|
|
||||||
|
|
||||||
|
HttpContext.Session.SetInt32("LastPizzaOrderId", order.Id);
|
||||||
|
|
||||||
|
TempData["Success"] = $"Tack {order.CustomerName}! Din pizza är beställd!";
|
||||||
|
return RedirectToAction("PizzaOrder");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[Authorize(Roles = "Chef")]
|
||||||
|
public IActionResult PizzaAdmin(DateTime? date)
|
||||||
|
{
|
||||||
|
var selectedDate = date ?? DateTime.Today;
|
||||||
|
var nextDay = selectedDate.AddDays(1);
|
||||||
|
|
||||||
|
var allOrders = _context.PizzaOrders
|
||||||
|
.Where(o => o.OrderedAt >= selectedDate && o.OrderedAt < nextDay)
|
||||||
|
.OrderBy(o => o.OrderedAt)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
ViewBag.ActiveOrders = allOrders
|
||||||
|
.Where(o => o.Status != "Klar")
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
ViewBag.CompletedOrders = allOrders
|
||||||
|
.Where(o => o.Status == "Klar")
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
return View();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
[Authorize(Roles = "Chef")]
|
||||||
|
public IActionResult UpdatePizzaOrder(int id, string status, string ingredientsJson)
|
||||||
|
{
|
||||||
|
var order = _context.PizzaOrders.FirstOrDefault(p => p.Id == id);
|
||||||
|
if (order != null)
|
||||||
|
{
|
||||||
|
order.Status = status;
|
||||||
|
order.IngredientsJson = ingredientsJson;
|
||||||
|
_context.SaveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
return RedirectToAction("PizzaAdmin");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Authorize(Roles = "Chef")]
|
||||||
public IActionResult Veckomeny(int? week, int? year)
|
public IActionResult Veckomeny(int? week, int? year)
|
||||||
{
|
{
|
||||||
var menuService = new MenuService(_configuration, _env);
|
var menuService = new MenuService(_configuration, _env);
|
||||||
|
|||||||
15
Aberwyn/Controllers/LoginController.cs
Normal file
15
Aberwyn/Controllers/LoginController.cs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace Aberwyn.Controllers
|
||||||
|
{
|
||||||
|
public class LoginController : Controller
|
||||||
|
{
|
||||||
|
[HttpGet]
|
||||||
|
public IActionResult Login(string returnUrl = "/")
|
||||||
|
{
|
||||||
|
ViewBag.ReturnUrl = returnUrl;
|
||||||
|
return View(); // View måste heta "Login.cshtml"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
58
Aberwyn/Controllers/PizzaController.cs
Normal file
58
Aberwyn/Controllers/PizzaController.cs
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Aberwyn.Data;
|
||||||
|
using Aberwyn.Models;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Aberwyn.Controllers
|
||||||
|
{
|
||||||
|
public class PizzaController : Controller
|
||||||
|
{
|
||||||
|
private readonly MenuService _menuService;
|
||||||
|
private readonly ApplicationDbContext _context;
|
||||||
|
|
||||||
|
public PizzaController(MenuService menuService, ApplicationDbContext context)
|
||||||
|
{
|
||||||
|
_menuService = menuService;
|
||||||
|
_context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
public IActionResult Order()
|
||||||
|
{
|
||||||
|
var pizzas = _menuService.GetMeals()
|
||||||
|
.Where(m => m.Name.ToLower().Contains("pizza"))
|
||||||
|
.OrderBy(m => m.Name)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
var orders = _context.PizzaOrders
|
||||||
|
.OrderByDescending(o => o.OrderedAt)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
ViewBag.Pizzas = pizzas;
|
||||||
|
ViewBag.ExistingOrders = orders;
|
||||||
|
return View();
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
public IActionResult Order(string customerName, string pizzaName)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(customerName) || string.IsNullOrWhiteSpace(pizzaName))
|
||||||
|
{
|
||||||
|
TempData["Error"] = "Både namn och pizza måste anges.";
|
||||||
|
return RedirectToAction("Order");
|
||||||
|
}
|
||||||
|
|
||||||
|
var order = new PizzaOrder
|
||||||
|
{
|
||||||
|
CustomerName = customerName.Trim(),
|
||||||
|
PizzaName = pizzaName.Trim()
|
||||||
|
};
|
||||||
|
|
||||||
|
_context.PizzaOrders.Add(order);
|
||||||
|
_context.SaveChanges();
|
||||||
|
|
||||||
|
TempData["Success"] = "Beställningen har lagts!";
|
||||||
|
return RedirectToAction("Order");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,5 +15,7 @@ namespace Aberwyn.Data
|
|||||||
public DbSet<BudgetCategory> BudgetCategories { get; set; }
|
public DbSet<BudgetCategory> BudgetCategories { get; set; }
|
||||||
public DbSet<BudgetItem> BudgetItems { get; set; }
|
public DbSet<BudgetItem> BudgetItems { get; set; }
|
||||||
public DbSet<PushSubscriber> PushSubscribers { get; set; }
|
public DbSet<PushSubscriber> PushSubscribers { get; set; }
|
||||||
|
public DbSet<PizzaOrder> PizzaOrders { get; set; }
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -471,6 +471,61 @@ namespace Aberwyn.Data
|
|||||||
SaveIngredients(meal.Id, meal.Ingredients);
|
SaveIngredients(meal.Id, meal.Ingredients);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public List<Meal> GetMealsByCategory(string category)
|
||||||
|
{
|
||||||
|
var meals = new List<Meal>();
|
||||||
|
|
||||||
|
using var connection = GetConnection();
|
||||||
|
connection.Open();
|
||||||
|
|
||||||
|
string query = @"
|
||||||
|
SELECT m.Id, m.Name, m.Category, m.Description, m.ImageUrl, m.ImageData, m.ImageMimeType,
|
||||||
|
i.Id AS IngredientId, i.Quantity, i.Item
|
||||||
|
FROM Meals m
|
||||||
|
LEFT JOIN Ingredients i ON m.Id = i.MealId
|
||||||
|
WHERE m.Category = @category
|
||||||
|
ORDER BY m.Name, i.Id";
|
||||||
|
|
||||||
|
using var cmd = new MySqlCommand(query, connection);
|
||||||
|
cmd.Parameters.AddWithValue("@category", category);
|
||||||
|
|
||||||
|
using var reader = cmd.ExecuteReader();
|
||||||
|
Dictionary<int, Meal> mealMap = new();
|
||||||
|
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
int mealId = reader.GetInt32("Id");
|
||||||
|
|
||||||
|
if (!mealMap.ContainsKey(mealId))
|
||||||
|
{
|
||||||
|
mealMap[mealId] = new Meal
|
||||||
|
{
|
||||||
|
Id = mealId,
|
||||||
|
Name = reader.GetString("Name"),
|
||||||
|
Category = reader.IsDBNull(reader.GetOrdinal("Category")) ? null : reader.GetString("Category"),
|
||||||
|
Description = reader.IsDBNull(reader.GetOrdinal("Description")) ? null : reader.GetString("Description"),
|
||||||
|
ImageUrl = reader.IsDBNull(reader.GetOrdinal("ImageUrl")) ? null : reader.GetString("ImageUrl"),
|
||||||
|
ImageData = reader.IsDBNull(reader.GetOrdinal("ImageData")) ? null : (byte[])reader["ImageData"],
|
||||||
|
ImageMimeType = reader.IsDBNull(reader.GetOrdinal("ImageMimeType")) ? null : reader.GetString("ImageMimeType"),
|
||||||
|
Ingredients = new List<Ingredient>()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!reader.IsDBNull(reader.GetOrdinal("IngredientId")))
|
||||||
|
{
|
||||||
|
mealMap[mealId].Ingredients.Add(new Ingredient
|
||||||
|
{
|
||||||
|
Id = reader.GetInt32("IngredientId"),
|
||||||
|
MealId = mealId,
|
||||||
|
Quantity = reader.IsDBNull(reader.GetOrdinal("Quantity")) ? "" : reader.GetString("Quantity"),
|
||||||
|
Item = reader.IsDBNull(reader.GetOrdinal("Item")) ? "" : reader.GetString("Item")
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return mealMap.Values.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
public List<WeeklyMenu> GetMenuEntriesByDateRange(DateTime startDate, DateTime endDate)
|
public List<WeeklyMenu> GetMenuEntriesByDateRange(DateTime startDate, DateTime endDate)
|
||||||
{
|
{
|
||||||
var results = new List<WeeklyMenu>();
|
var results = new List<WeeklyMenu>();
|
||||||
|
|||||||
403
Aberwyn/Migrations/20250524103706_AddPizzaOrder.Designer.cs
generated
Normal file
403
Aberwyn/Migrations/20250524103706_AddPizzaOrder.Designer.cs
generated
Normal file
@@ -0,0 +1,403 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using Aberwyn.Data;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Aberwyn.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(ApplicationDbContext))]
|
||||||
|
[Migration("20250524103706_AddPizzaOrder")]
|
||||||
|
partial class AddPizzaOrder
|
||||||
|
{
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "6.0.36")
|
||||||
|
.HasAnnotation("Relational:MaxIdentifierLength", 64);
|
||||||
|
|
||||||
|
modelBuilder.Entity("Aberwyn.Models.ApplicationUser", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.Property<int>("AccessFailedCount")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("ConcurrencyStamp")
|
||||||
|
.IsConcurrencyToken()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("Email")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("varchar(256)");
|
||||||
|
|
||||||
|
b.Property<bool>("EmailConfirmed")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<bool>("LockoutEnabled")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset?>("LockoutEnd")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("NormalizedEmail")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("varchar(256)");
|
||||||
|
|
||||||
|
b.Property<string>("NormalizedUserName")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("varchar(256)");
|
||||||
|
|
||||||
|
b.Property<string>("PasswordHash")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("PhoneNumber")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<bool>("PhoneNumberConfirmed")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<string>("SecurityStamp")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<bool>("TwoFactorEnabled")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<string>("UserName")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("varchar(256)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("NormalizedEmail")
|
||||||
|
.HasDatabaseName("EmailIndex");
|
||||||
|
|
||||||
|
b.HasIndex("NormalizedUserName")
|
||||||
|
.IsUnique()
|
||||||
|
.HasDatabaseName("UserNameIndex");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUsers", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Aberwyn.Models.BudgetCategory", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int>("BudgetPeriodId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Color")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<int>("Order")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("BudgetPeriodId");
|
||||||
|
|
||||||
|
b.ToTable("BudgetCategories");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Aberwyn.Models.BudgetItem", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<decimal>("Amount")
|
||||||
|
.HasColumnType("decimal(65,30)");
|
||||||
|
|
||||||
|
b.Property<int>("BudgetCategoryId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<bool>("IncludeInSummary")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<bool>("IsExpense")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<int>("Order")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("BudgetCategoryId");
|
||||||
|
|
||||||
|
b.ToTable("BudgetItems");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Aberwyn.Models.BudgetPeriod", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int>("Month")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int>("Order")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int>("Year")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("BudgetPeriods");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Aberwyn.Models.PushSubscriber", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Auth")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("Endpoint")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("P256DH")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("PushSubscribers");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.Property<string>("ConcurrencyStamp")
|
||||||
|
.IsConcurrencyToken()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("varchar(256)");
|
||||||
|
|
||||||
|
b.Property<string>("NormalizedName")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("varchar(256)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("NormalizedName")
|
||||||
|
.IsUnique()
|
||||||
|
.HasDatabaseName("RoleNameIndex");
|
||||||
|
|
||||||
|
b.ToTable("AspNetRoles", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("ClaimType")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("ClaimValue")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("RoleId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("RoleId");
|
||||||
|
|
||||||
|
b.ToTable("AspNetRoleClaims", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("ClaimType")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("ClaimValue")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUserClaims", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("LoginProvider")
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.Property<string>("ProviderKey")
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.Property<string>("ProviderDisplayName")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.HasKey("LoginProvider", "ProviderKey");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUserLogins", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.Property<string>("RoleId")
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.HasKey("UserId", "RoleId");
|
||||||
|
|
||||||
|
b.HasIndex("RoleId");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUserRoles", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.Property<string>("LoginProvider")
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.Property<string>("Value")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.HasKey("UserId", "LoginProvider", "Name");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUserTokens", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Aberwyn.Models.BudgetCategory", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Aberwyn.Models.BudgetPeriod", "BudgetPeriod")
|
||||||
|
.WithMany("Categories")
|
||||||
|
.HasForeignKey("BudgetPeriodId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("BudgetPeriod");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Aberwyn.Models.BudgetItem", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Aberwyn.Models.BudgetCategory", "BudgetCategory")
|
||||||
|
.WithMany("Items")
|
||||||
|
.HasForeignKey("BudgetCategoryId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("BudgetCategory");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("RoleId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Aberwyn.Models.ApplicationUser", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Aberwyn.Models.ApplicationUser", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("RoleId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("Aberwyn.Models.ApplicationUser", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Aberwyn.Models.ApplicationUser", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Aberwyn.Models.BudgetCategory", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Items");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Aberwyn.Models.BudgetPeriod", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Categories");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
19
Aberwyn/Migrations/20250524103706_AddPizzaOrder.cs
Normal file
19
Aberwyn/Migrations/20250524103706_AddPizzaOrder.cs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Aberwyn.Migrations
|
||||||
|
{
|
||||||
|
public partial class AddPizzaOrder : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
432
Aberwyn/Migrations/20250524121511_AddPizzaOrderTable.Designer.cs
generated
Normal file
432
Aberwyn/Migrations/20250524121511_AddPizzaOrderTable.Designer.cs
generated
Normal file
@@ -0,0 +1,432 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using Aberwyn.Data;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Aberwyn.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(ApplicationDbContext))]
|
||||||
|
[Migration("20250524121511_AddPizzaOrderTable")]
|
||||||
|
partial class AddPizzaOrderTable
|
||||||
|
{
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "6.0.36")
|
||||||
|
.HasAnnotation("Relational:MaxIdentifierLength", 64);
|
||||||
|
|
||||||
|
modelBuilder.Entity("Aberwyn.Models.ApplicationUser", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.Property<int>("AccessFailedCount")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("ConcurrencyStamp")
|
||||||
|
.IsConcurrencyToken()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("Email")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("varchar(256)");
|
||||||
|
|
||||||
|
b.Property<bool>("EmailConfirmed")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<bool>("LockoutEnabled")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset?>("LockoutEnd")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("NormalizedEmail")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("varchar(256)");
|
||||||
|
|
||||||
|
b.Property<string>("NormalizedUserName")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("varchar(256)");
|
||||||
|
|
||||||
|
b.Property<string>("PasswordHash")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("PhoneNumber")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<bool>("PhoneNumberConfirmed")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<string>("SecurityStamp")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<bool>("TwoFactorEnabled")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<string>("UserName")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("varchar(256)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("NormalizedEmail")
|
||||||
|
.HasDatabaseName("EmailIndex");
|
||||||
|
|
||||||
|
b.HasIndex("NormalizedUserName")
|
||||||
|
.IsUnique()
|
||||||
|
.HasDatabaseName("UserNameIndex");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUsers", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Aberwyn.Models.BudgetCategory", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int>("BudgetPeriodId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Color")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<int>("Order")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("BudgetPeriodId");
|
||||||
|
|
||||||
|
b.ToTable("BudgetCategories");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Aberwyn.Models.BudgetItem", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<decimal>("Amount")
|
||||||
|
.HasColumnType("decimal(65,30)");
|
||||||
|
|
||||||
|
b.Property<int>("BudgetCategoryId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<bool>("IncludeInSummary")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<bool>("IsExpense")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<int>("Order")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("BudgetCategoryId");
|
||||||
|
|
||||||
|
b.ToTable("BudgetItems");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Aberwyn.Models.BudgetPeriod", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int>("Month")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int>("Order")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int>("Year")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("BudgetPeriods");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Aberwyn.Models.PizzaOrder", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("CustomerName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("IngredientsJson")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<DateTime>("OrderedAt")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("PizzaName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("Status")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("PizzaOrders");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Aberwyn.Models.PushSubscriber", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Auth")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("Endpoint")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("P256DH")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("PushSubscribers");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.Property<string>("ConcurrencyStamp")
|
||||||
|
.IsConcurrencyToken()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("varchar(256)");
|
||||||
|
|
||||||
|
b.Property<string>("NormalizedName")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("varchar(256)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("NormalizedName")
|
||||||
|
.IsUnique()
|
||||||
|
.HasDatabaseName("RoleNameIndex");
|
||||||
|
|
||||||
|
b.ToTable("AspNetRoles", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("ClaimType")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("ClaimValue")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("RoleId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("RoleId");
|
||||||
|
|
||||||
|
b.ToTable("AspNetRoleClaims", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("ClaimType")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("ClaimValue")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUserClaims", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("LoginProvider")
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.Property<string>("ProviderKey")
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.Property<string>("ProviderDisplayName")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.HasKey("LoginProvider", "ProviderKey");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUserLogins", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.Property<string>("RoleId")
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.HasKey("UserId", "RoleId");
|
||||||
|
|
||||||
|
b.HasIndex("RoleId");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUserRoles", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.Property<string>("LoginProvider")
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.Property<string>("Value")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.HasKey("UserId", "LoginProvider", "Name");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUserTokens", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Aberwyn.Models.BudgetCategory", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Aberwyn.Models.BudgetPeriod", "BudgetPeriod")
|
||||||
|
.WithMany("Categories")
|
||||||
|
.HasForeignKey("BudgetPeriodId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("BudgetPeriod");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Aberwyn.Models.BudgetItem", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Aberwyn.Models.BudgetCategory", "BudgetCategory")
|
||||||
|
.WithMany("Items")
|
||||||
|
.HasForeignKey("BudgetCategoryId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("BudgetCategory");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("RoleId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Aberwyn.Models.ApplicationUser", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Aberwyn.Models.ApplicationUser", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("RoleId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("Aberwyn.Models.ApplicationUser", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Aberwyn.Models.ApplicationUser", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Aberwyn.Models.BudgetCategory", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Items");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Aberwyn.Models.BudgetPeriod", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Categories");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
42
Aberwyn/Migrations/20250524121511_AddPizzaOrderTable.cs
Normal file
42
Aberwyn/Migrations/20250524121511_AddPizzaOrderTable.cs
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Aberwyn.Migrations
|
||||||
|
{
|
||||||
|
public partial class AddPizzaOrderTable : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "PizzaOrders",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "int", nullable: false)
|
||||||
|
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
||||||
|
CustomerName = table.Column<string>(type: "longtext", nullable: false)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||||
|
PizzaName = table.Column<string>(type: "longtext", nullable: false)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||||
|
IngredientsJson = table.Column<string>(type: "longtext", nullable: true)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||||
|
Status = table.Column<string>(type: "longtext", nullable: false)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||||
|
OrderedAt = table.Column<DateTime>(type: "datetime(6)", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_PizzaOrders", x => x.Id);
|
||||||
|
})
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "PizzaOrders");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -162,6 +162,35 @@ namespace Aberwyn.Migrations
|
|||||||
b.ToTable("BudgetPeriods");
|
b.ToTable("BudgetPeriods");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Aberwyn.Models.PizzaOrder", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("CustomerName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("IngredientsJson")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<DateTime>("OrderedAt")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("PizzaName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("Status")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("PizzaOrders");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Aberwyn.Models.PushSubscriber", b =>
|
modelBuilder.Entity("Aberwyn.Models.PushSubscriber", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ namespace Aberwyn.Models
|
|||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public string Description { get; set; }
|
public string Description { get; set; }
|
||||||
public string ProteinType { get; set; }
|
public string ProteinType { get; set; }
|
||||||
|
public string Category { get; set; }
|
||||||
public string CarbType { get; set; }
|
public string CarbType { get; set; }
|
||||||
public string RecipeUrl { get; set; }
|
public string RecipeUrl { get; set; }
|
||||||
public string ImageUrl { get; set; }
|
public string ImageUrl { get; set; }
|
||||||
@@ -61,6 +62,8 @@ namespace Aberwyn.Models
|
|||||||
{
|
{
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
public string Category { get; set; }
|
||||||
|
|
||||||
public string? ImageUrl { get; set; }
|
public string? ImageUrl { get; set; }
|
||||||
public string? ImageData { get; set; } // base64
|
public string? ImageData { get; set; } // base64
|
||||||
public string? ImageMimeType { get; set; }
|
public string? ImageMimeType { get; set; }
|
||||||
@@ -71,6 +74,7 @@ namespace Aberwyn.Models
|
|||||||
{
|
{
|
||||||
Id = meal.Id,
|
Id = meal.Id,
|
||||||
Name = meal.Name,
|
Name = meal.Name,
|
||||||
|
Category = meal.Category,
|
||||||
ImageUrl = meal.ImageUrl,
|
ImageUrl = meal.ImageUrl,
|
||||||
ImageMimeType = meal.ImageMimeType,
|
ImageMimeType = meal.ImageMimeType,
|
||||||
ImageData = meal.ImageData != null ? Convert.ToBase64String(meal.ImageData) : null
|
ImageData = meal.ImageData != null ? Convert.ToBase64String(meal.ImageData) : null
|
||||||
|
|||||||
22
Aberwyn/Models/PizzaOrder.cs
Normal file
22
Aberwyn/Models/PizzaOrder.cs
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace Aberwyn.Models
|
||||||
|
{
|
||||||
|
public class PizzaOrder
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public string CustomerName { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public string PizzaName { get; set; }
|
||||||
|
|
||||||
|
public string? IngredientsJson { get; set; } // lista i JSON-form
|
||||||
|
|
||||||
|
public string Status { get; set; } = "Ej bekräftad"; // "Ej bekräftad", "Bekräftad", "Klar"
|
||||||
|
|
||||||
|
public DateTime OrderedAt { get; set; } = DateTime.Now;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -21,6 +21,12 @@ builder.Services.AddControllersWithViews()
|
|||||||
// Ignorera null-v<>rden vid serialisering
|
// Ignorera null-v<>rden vid serialisering
|
||||||
opts.JsonSerializerOptions.IgnoreNullValues = true;
|
opts.JsonSerializerOptions.IgnoreNullValues = true;
|
||||||
});
|
});
|
||||||
|
builder.Services.AddSession(options =>
|
||||||
|
{
|
||||||
|
options.IdleTimeout = TimeSpan.FromHours(1);
|
||||||
|
options.Cookie.HttpOnly = true;
|
||||||
|
options.Cookie.IsEssential = true;
|
||||||
|
});
|
||||||
|
|
||||||
builder.Services.AddRazorPages();
|
builder.Services.AddRazorPages();
|
||||||
builder.Services.AddHttpClient();
|
builder.Services.AddHttpClient();
|
||||||
@@ -64,8 +70,10 @@ builder.Services.AddSingleton<PushNotificationService>(sp =>
|
|||||||
});
|
});
|
||||||
|
|
||||||
builder.Services.Configure<VapidOptions>(builder.Configuration.GetSection("Vapid"));
|
builder.Services.Configure<VapidOptions>(builder.Configuration.GetSection("Vapid"));
|
||||||
|
builder.Services.ConfigureApplicationCookie(options =>
|
||||||
|
{
|
||||||
|
options.LoginPath = "/Identity/Account/Login"; // korrekt för ditt nuvarande upplägg
|
||||||
|
});
|
||||||
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
||||||
builder.Services.Configure<RequestLocalizationOptions>(options =>
|
builder.Services.Configure<RequestLocalizationOptions>(options =>
|
||||||
{
|
{
|
||||||
@@ -99,6 +107,7 @@ if (!app.Environment.IsDevelopment())
|
|||||||
|
|
||||||
app.UseStaticFiles();
|
app.UseStaticFiles();
|
||||||
app.UseRouting();
|
app.UseRouting();
|
||||||
|
app.UseSession();
|
||||||
app.UseAuthentication();;
|
app.UseAuthentication();;
|
||||||
app.UseAuthorization();
|
app.UseAuthorization();
|
||||||
|
|
||||||
|
|||||||
145
Aberwyn/Views/FoodMenu/PizzaAdmin.cshtml
Normal file
145
Aberwyn/Views/FoodMenu/PizzaAdmin.cshtml
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
@using Newtonsoft.Json
|
||||||
|
@using Newtonsoft.Json.Serialization
|
||||||
|
@{
|
||||||
|
ViewData["Title"] = "Pizza Admin";
|
||||||
|
var activeOrders = ViewBag.ActiveOrders as List<PizzaOrder> ?? new List<PizzaOrder>();
|
||||||
|
var completedOrders = ViewBag.CompletedOrders as List<PizzaOrder> ?? new List<PizzaOrder>();
|
||||||
|
}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.card {
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
|
||||||
|
transition: transform 0.2s ease-in-out;
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
flex: 1 1 260px;
|
||||||
|
min-width: 240px;
|
||||||
|
max-width: 280px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-header {
|
||||||
|
font-weight: bold;
|
||||||
|
padding: 10px 12px;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-body {
|
||||||
|
padding: 12px;
|
||||||
|
flex-grow: 1;
|
||||||
|
background-color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.border-info .card-header {
|
||||||
|
background-color: #0dcaf0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.border-warning .card-header {
|
||||||
|
background-color: #ffc107;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.border-success .card-header {
|
||||||
|
background-color: #28a745;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card .btn {
|
||||||
|
font-weight: 600;
|
||||||
|
flex: 1 1 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card ul {
|
||||||
|
margin-bottom: 0;
|
||||||
|
padding-left: 1.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-grid {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 16px;
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@media only screen and (max-width: 600px) {
|
||||||
|
.card {
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<h2 class="mt-4">Aktiva beställningar</h2>
|
||||||
|
<div class="card-grid">
|
||||||
|
@foreach (var order in activeOrders)
|
||||||
|
{
|
||||||
|
var ingredients = new List<string>();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(order.IngredientsJson))
|
||||||
|
{
|
||||||
|
ingredients = System.Text.Json.JsonSerializer.Deserialize<List<string>>(order.IngredientsJson);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
ingredients = order.IngredientsJson.Split('\n').ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
var cardClass = order.Status switch
|
||||||
|
{
|
||||||
|
"Bekräftad" => "border-warning",
|
||||||
|
"Klar" => "border-success",
|
||||||
|
_ => "border-info"
|
||||||
|
};
|
||||||
|
|
||||||
|
<div class="card @cardClass">
|
||||||
|
<div class="card-header">@order.CustomerName</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="fw-bold mb-1">@order.PizzaName</div>
|
||||||
|
<ul class="mb-2">
|
||||||
|
@foreach (var ing in ingredients)
|
||||||
|
{
|
||||||
|
<li>@ing</li>
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
<form id="form-@order.Id" method="post" asp-action="UpdatePizzaOrder">
|
||||||
|
<input type="hidden" name="id" value="@order.Id" />
|
||||||
|
<input type="hidden" name="ingredientsJson" value='@System.Text.Json.JsonSerializer.Serialize(ingredients)' />
|
||||||
|
<div class="d-flex gap-2">
|
||||||
|
@if (order.Status == "Ej bekräftad")
|
||||||
|
{
|
||||||
|
<input type="hidden" name="status" value="Bekräftad" />
|
||||||
|
<button type="submit" class="btn btn-sm btn-outline-primary">Bekräfta</button>
|
||||||
|
}
|
||||||
|
else if (order.Status == "Bekräftad")
|
||||||
|
{
|
||||||
|
<input type="hidden" name="status" value="Klar" />
|
||||||
|
<button type="submit" class="btn btn-sm btn-outline-success">✔ Klar</button>
|
||||||
|
}
|
||||||
|
<button type="submit" formaction="@Url.Action("UpdatePizzaOrder", new { status = "Neka", id = order.Id })" class="btn btn-sm btn-outline-danger">Neka</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2 class="mt-5">Färdiga pizzor</h2>
|
||||||
|
@if (completedOrders.Any())
|
||||||
|
{
|
||||||
|
<ul class="list-group">
|
||||||
|
@foreach (var order in completedOrders)
|
||||||
|
{
|
||||||
|
<li class="list-group-item">
|
||||||
|
@order.CustomerName – @order.PizzaName
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<div class="text-muted">Inga pizzor är klara ännu.</div>
|
||||||
|
}
|
||||||
226
Aberwyn/Views/FoodMenu/PizzaOrder.cshtml
Normal file
226
Aberwyn/Views/FoodMenu/PizzaOrder.cshtml
Normal file
@@ -0,0 +1,226 @@
|
|||||||
|
@using Newtonsoft.Json
|
||||||
|
@using Newtonsoft.Json.Serialization
|
||||||
|
@{
|
||||||
|
ViewData["Title"] = "Beställ pizza";
|
||||||
|
var pizzas = ViewBag.Pizzas as List<Meal>;
|
||||||
|
var previousOrder = ViewBag.PreviousOrder as PizzaOrder;
|
||||||
|
var lastId = Context.Session.GetInt32("LastPizzaOrderId");
|
||||||
|
var isCurrentOrder = previousOrder?.Id == lastId;
|
||||||
|
var forceShow = TempData["ForceShowForm"]?.ToString() == "true";
|
||||||
|
var justOrdered = TempData["Success"]?.ToString()?.Contains("beställd") == true;
|
||||||
|
var showForm = previousOrder == null || (forceShow && !justOrdered);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="~/css/pizza.css" />
|
||||||
|
|
||||||
|
<div class="pizza-container">
|
||||||
|
|
||||||
|
@if (TempData["Success"] != null)
|
||||||
|
{
|
||||||
|
<div class="alert alert-success text-center mb-4">
|
||||||
|
🍕 @TempData["Success"]
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
@if (previousOrder != null)
|
||||||
|
{
|
||||||
|
var ingredienser = string.IsNullOrEmpty(previousOrder.IngredientsJson)
|
||||||
|
? new List<string>()
|
||||||
|
: System.Text.Json.JsonSerializer.Deserialize<List<string>>(previousOrder.IngredientsJson);
|
||||||
|
|
||||||
|
<div class="alert alert-info mb-4">
|
||||||
|
<strong>🍕 Du har redan beställt:</strong><br />
|
||||||
|
<strong>@previousOrder.PizzaName</strong>
|
||||||
|
@if (ingredienser.Count > 0)
|
||||||
|
{
|
||||||
|
<span>(med @string.Join(", ", ingredienser))</span>
|
||||||
|
}
|
||||||
|
<div class="mt-2">
|
||||||
|
<span class="badge bg-secondary">Status: @previousOrder.Status</span>
|
||||||
|
</div>
|
||||||
|
<form method="get" asp-action="EditPizzaOrder" asp-route-id="@previousOrder.Id" class="d-inline mt-2">
|
||||||
|
<button class="btn btn-sm btn-outline-primary me-2">✏️ Uppdatera min beställning</button>
|
||||||
|
</form>
|
||||||
|
<form method="post" asp-action="ClearPizzaSession" class="d-inline">
|
||||||
|
<button class="btn btn-sm btn-outline-secondary">➕ Beställ ny pizza</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
@if (showForm)
|
||||||
|
{
|
||||||
|
<!-- Steg 1: Namn -->
|
||||||
|
<div id="step1" class="pizza-step active">
|
||||||
|
<h2>Hej! Vad heter du? 😊</h2>
|
||||||
|
<input type="text" id="customerName" placeholder="Ditt namn" class="form-control" />
|
||||||
|
<button onclick="goToStep(2)" class="btn btn-primary mt-3">Fortsätt</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Steg 2: Välj pizza -->
|
||||||
|
<div id="step2" class="pizza-step">
|
||||||
|
<h2>🍕 Välj en pizza</h2>
|
||||||
|
<div class="pizza-list">
|
||||||
|
@foreach (var pizza in pizzas)
|
||||||
|
{
|
||||||
|
<div class="pizza-card" onclick="selectPizza(@pizza.Id)">
|
||||||
|
<h3>@pizza.Name</h3>
|
||||||
|
<p>@string.Join(", ", pizza.Ingredients?.Select(i => i.Item) ?? new List<string>())</p>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
<div class="pizza-card custom" onclick="selectPizza(null)">
|
||||||
|
<h3>🧑🍳 Skapa egen pizza</h3>
|
||||||
|
<p>Lägg till dina egna ingredienser</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Steg 3: Redigera ingredienser -->
|
||||||
|
<div id="step3" class="pizza-step">
|
||||||
|
<h2 id="editTitle">Redigera pizza</h2>
|
||||||
|
<ul id="ingredientList" class="list-group mb-3"></ul>
|
||||||
|
<div class="input-group mb-3">
|
||||||
|
<input type="text" id="newIngredient" class="form-control" placeholder="Lägg till ingrediens" />
|
||||||
|
<button type="button" class="btn btn-outline-secondary" onclick="addIngredient()">➕</button>
|
||||||
|
</div>
|
||||||
|
<button class="btn btn-secondary" onclick="goToStep(2)">⬅ Tillbaka</button>
|
||||||
|
<button class="btn btn-primary" onclick="goToStep(4)">Fortsätt</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Steg 4: Summering -->
|
||||||
|
<div id="step4" class="pizza-step">
|
||||||
|
<h2>Bekräfta din beställning</h2>
|
||||||
|
<p>Din pizza:</p>
|
||||||
|
<p><strong id="summaryPizza"></strong></p>
|
||||||
|
<ul id="summaryIngredients" class="list-group mb-3"></ul>
|
||||||
|
|
||||||
|
<form method="post">
|
||||||
|
<input type="hidden" name="customerName" id="formName" />
|
||||||
|
<input type="hidden" name="pizzaName" id="formPizza" />
|
||||||
|
<input type="hidden" name="ingredients" id="formIngredients" />
|
||||||
|
<button type="submit" class="btn btn-success">✅ Skicka beställning</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@section Scripts {
|
||||||
|
<script>
|
||||||
|
@if (ViewBag.PreviousOrder is PizzaOrder p)
|
||||||
|
{
|
||||||
|
<text>
|
||||||
|
window.addEventListener("DOMContentLoaded", () => {
|
||||||
|
const forceEdit = @((TempData["ForceShowForm"]?.ToString() == "true").ToString().ToLower());
|
||||||
|
const customerField = document.getElementById("customerName");
|
||||||
|
if (customerField) customerField.value = "@p.CustomerName";
|
||||||
|
const selected = allMeals.find(m => m.name === "@p.PizzaName") || { name: "Egen pizza", ingredients: [] };
|
||||||
|
if (forceEdit && selected) {
|
||||||
|
selectedPizza = selected;
|
||||||
|
selectedIngredients = @Html.Raw(p.IngredientsJson ?? "[]");
|
||||||
|
document.getElementById("editTitle").innerText = `Redigera: ${selected.name}`;
|
||||||
|
renderIngredientList();
|
||||||
|
selectedName = "@p.CustomerName";
|
||||||
|
goToStep(3);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</text>
|
||||||
|
}
|
||||||
|
|
||||||
|
const allMeals = @Html.Raw(JsonConvert.SerializeObject(
|
||||||
|
pizzas,
|
||||||
|
new JsonSerializerSettings {
|
||||||
|
NullValueHandling = NullValueHandling.Ignore,
|
||||||
|
ContractResolver = new CamelCasePropertyNamesContractResolver()
|
||||||
|
}));
|
||||||
|
|
||||||
|
let selectedPizza = null;
|
||||||
|
let selectedIngredients = [];
|
||||||
|
let selectedName = "";
|
||||||
|
|
||||||
|
function goToStep(step) {
|
||||||
|
if (step === 2) {
|
||||||
|
const nameInput = document.getElementById("customerName").value.trim();
|
||||||
|
if (!nameInput) {
|
||||||
|
alert("Skriv ditt namn!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
selectedName = nameInput;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (step === 4) {
|
||||||
|
const pizzaName = selectedPizza?.name ?? "Egen pizza";
|
||||||
|
const originalIngredients = selectedPizza?.ingredients?.map(i => i.item) ?? [];
|
||||||
|
const current = selectedIngredients;
|
||||||
|
|
||||||
|
const removed = [];
|
||||||
|
const added = [];
|
||||||
|
|
||||||
|
let details = [];
|
||||||
|
if (removed.length > 0) details.push("utan " + removed.join(", "));
|
||||||
|
if (added.length > 0) details.push("extra " + added.join(", "));
|
||||||
|
|
||||||
|
const fullName = details.length > 0
|
||||||
|
? `${pizzaName} (${details.join(", ")})`
|
||||||
|
: pizzaName;
|
||||||
|
|
||||||
|
document.getElementById("summaryPizza").innerText = fullName;
|
||||||
|
document.getElementById("formName").value = selectedName;
|
||||||
|
document.getElementById("formPizza").value = fullName;
|
||||||
|
document.getElementById("formIngredients").value = JSON.stringify(selectedIngredients);
|
||||||
|
const list = document.getElementById("summaryIngredients");
|
||||||
|
list.innerHTML = '';
|
||||||
|
selectedIngredients.forEach(ing => {
|
||||||
|
const li = document.createElement("li");
|
||||||
|
li.className = "list-group-item";
|
||||||
|
li.innerText = ing;
|
||||||
|
list.appendChild(li);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
document.querySelectorAll(".pizza-step").forEach(s => s.classList.remove("active"));
|
||||||
|
document.getElementById(`step${step}`)?.classList.add("active");
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectPizza(pizzaId) {
|
||||||
|
pizzaId = parseInt(pizzaId);
|
||||||
|
selectedPizza = allMeals.find(m => m.id === pizzaId);
|
||||||
|
if (!selectedPizza) {
|
||||||
|
selectedPizza = { name: "Egen pizza", ingredients: [] };
|
||||||
|
}
|
||||||
|
selectedIngredients = [...(selectedPizza.ingredients?.map(i => i.item) ?? [])];
|
||||||
|
document.getElementById("editTitle").innerText = `Redigera: ${selectedPizza.name}`;
|
||||||
|
renderIngredientList();
|
||||||
|
goToStep(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderIngredientList() {
|
||||||
|
const list = document.getElementById("ingredientList");
|
||||||
|
list.innerHTML = '';
|
||||||
|
selectedIngredients.forEach((ing, i) => {
|
||||||
|
const li = document.createElement("li");
|
||||||
|
li.className = "list-group-item d-flex justify-content-between";
|
||||||
|
li.innerHTML = `${ing} <button class="btn btn-sm btn-danger" onclick="removeIngredient(${i})">🗑</button>`;
|
||||||
|
list.appendChild(li);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function addIngredient() {
|
||||||
|
const input = document.getElementById("newIngredient");
|
||||||
|
const value = input.value.trim();
|
||||||
|
if (value) {
|
||||||
|
selectedIngredients.push(value);
|
||||||
|
input.value = '';
|
||||||
|
renderIngredientList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeIngredient(index) {
|
||||||
|
selectedIngredients.splice(index, 1);
|
||||||
|
renderIngredientList();
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById("customerName")?.addEventListener("keydown", function (e) {
|
||||||
|
if (e.key === "Enter") goToStep(2);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
}
|
||||||
21
Aberwyn/Views/Login/Index.cshtml
Normal file
21
Aberwyn/Views/Login/Index.cshtml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
@{
|
||||||
|
ViewData["Title"] = "Logga in";
|
||||||
|
var returnUrl = ViewBag.ReturnUrl as string ?? "/";
|
||||||
|
}
|
||||||
|
|
||||||
|
<h2>Logga in</h2>
|
||||||
|
|
||||||
|
<form method="post" asp-area="Identity" asp-page="/Account/Login">
|
||||||
|
<input type="hidden" name="returnUrl" value="@returnUrl" />
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="username" class="form-label">Användarnamn</label>
|
||||||
|
<input type="text" class="form-control" id="username" name="username" required />
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="password" class="form-label">Lösenord</label>
|
||||||
|
<input type="password" class="form-control" id="password" name="password" required />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit" class="btn btn-primary">Logga in</button>
|
||||||
|
</form>
|
||||||
174
Aberwyn/wwwroot/css/pizza.css
Normal file
174
Aberwyn/wwwroot/css/pizza.css
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
/* === PIZZERIA-INSPIRERAD STIL === */
|
||||||
|
|
||||||
|
.pizza-step {
|
||||||
|
display: none;
|
||||||
|
background-color: #fffaf0;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 24px;
|
||||||
|
box-shadow: 0 4px 10px rgba(0,0,0,0.1);
|
||||||
|
max-width: 600px;
|
||||||
|
margin: 2rem auto;
|
||||||
|
animation: fadeIn 0.3s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pizza-step.active {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pizza-step h2,
|
||||||
|
#editTitle {
|
||||||
|
font-family: 'Georgia', serif;
|
||||||
|
font-size: 1.8rem;
|
||||||
|
color: #a00000;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* === PIZZA LISTA === */
|
||||||
|
|
||||||
|
.pizza-list {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
gap: 1rem;
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 600px) {
|
||||||
|
.pizza-list {
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.pizza-card {
|
||||||
|
border: 2px solid #f4d5b3;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: #fff8e1;
|
||||||
|
padding: 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: transform 0.2s ease, border-color 0.2s;
|
||||||
|
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.06);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pizza-card:hover {
|
||||||
|
border-color: #e63946;
|
||||||
|
transform: scale(1.02);
|
||||||
|
background-color: #fff0dc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pizza-card h3 {
|
||||||
|
margin: 0;
|
||||||
|
color: #b30000;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pizza-card p {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: #555;
|
||||||
|
margin-top: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* === INGREDIENSER === */
|
||||||
|
|
||||||
|
#ingredientList {
|
||||||
|
list-style: none;
|
||||||
|
padding-left: 0;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ingredientList .list-group-item {
|
||||||
|
border: none;
|
||||||
|
border-bottom: 1px dashed #ccc;
|
||||||
|
font-family: 'Segoe UI', sans-serif;
|
||||||
|
font-size: 1rem;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 6px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* === KNAPPAR === */
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
font-weight: bold;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 8px 16px;
|
||||||
|
font-size: 1rem;
|
||||||
|
font-family: 'Segoe UI', sans-serif;
|
||||||
|
transition: all 0.2s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-outline-secondary,
|
||||||
|
.btn-outline-primary,
|
||||||
|
.btn-outline-danger {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-outline-secondary {
|
||||||
|
border: 2px solid #6a0dad;
|
||||||
|
color: #6a0dad;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-outline-secondary:hover {
|
||||||
|
background-color: #6a0dad;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary,
|
||||||
|
.btn-success {
|
||||||
|
background-color: #b30000;
|
||||||
|
border: 2px solid #b30000;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary:hover,
|
||||||
|
.btn-success:hover {
|
||||||
|
background-color: #cc0000;
|
||||||
|
border-color: #cc0000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-success {
|
||||||
|
background-color: #218838;
|
||||||
|
border-color: #218838;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-danger {
|
||||||
|
background-color: #dc3545;
|
||||||
|
border-color: #dc3545;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-danger:hover {
|
||||||
|
background-color: #c82333;
|
||||||
|
border-color: #bd2130;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* === FORM INPUT === */
|
||||||
|
|
||||||
|
.input-group input,
|
||||||
|
.input-group button {
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group button {
|
||||||
|
border-radius: 6px;
|
||||||
|
border: 2px solid #6a0dad;
|
||||||
|
background-color: white;
|
||||||
|
color: #6a0dad;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group button:hover {
|
||||||
|
background-color: #6a0dad;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* === ANIMATION === */
|
||||||
|
|
||||||
|
@keyframes fadeIn {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(10px);
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,7 +2,6 @@
|
|||||||
const urlsToCache = [
|
const urlsToCache = [
|
||||||
'/',
|
'/',
|
||||||
'/css/site.css',
|
'/css/site.css',
|
||||||
'/js/site.js',
|
|
||||||
'/images/lewel-icon.png',
|
'/images/lewel-icon.png',
|
||||||
'/manifest.json'
|
'/manifest.json'
|
||||||
];
|
];
|
||||||
@@ -15,12 +14,22 @@ self.addEventListener('install', event => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
self.addEventListener('fetch', event => {
|
self.addEventListener("fetch", function (event) {
|
||||||
|
const url = new URL(event.request.url);
|
||||||
|
|
||||||
|
// Hoppa över root / om du inte vill cachea den
|
||||||
|
if (url.pathname === "/") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Annars cacha som vanligt
|
||||||
event.respondWith(
|
event.respondWith(
|
||||||
caches.match(event.request)
|
caches.match(event.request).then(function (response) {
|
||||||
.then(response => response || fetch(event.request))
|
return response || fetch(event.request);
|
||||||
|
})
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
self.addEventListener('push', function (event) {
|
self.addEventListener('push', function (event) {
|
||||||
console.log("📨 Push event mottagen!", event);
|
console.log("📨 Push event mottagen!", event);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user