Compare commits

...

2 Commits

Author SHA1 Message Date
BuildTools
8ccbe8cf65 ModalComponent Show und Close-Funktionsnamen normiert 2024-06-26 20:37:49 +02:00
BuildTools
1e79620272 Angefangen, Gläser-Klasse zu implementieren 2024-06-26 20:37:17 +02:00
13 changed files with 246 additions and 17 deletions

View File

@ -3,7 +3,7 @@
"isRoot": true,
"tools": {
"dotnet-ef": {
"version": "8.0.0",
"version": "8.0.2",
"commands": [
"dotnet-ef"
]

View File

@ -10,8 +10,7 @@ namespace CocktailWeb.Data
public DbSet<CocktailFlasche> CocktailFlaschen { get; set; }
public DbSet<Cocktail> Cocktails { get; set; }
public DbSet<Filler> Fillers { get; set; }
public DbSet<Glas> Glaeser { get; set; }
public DbSet<Glas> Glasses { get; set; }
public DbDataContext(IConfiguration configuration)
{

View File

@ -3,9 +3,13 @@
public class Glas
{
public int Id { get; set; }
public string Name { get
public string? Name { get; set; }
public string DisplayName { get
{
return $"{Fuellmenge} ml";
string name = "";
if (Name != null) name += $"{Name} - ";
name += $"{Fuellmenge} ml";
return name;
}
}
public int Fuellmenge { get; set; }

Binary file not shown.

Binary file not shown.

View File

View File

@ -33,7 +33,7 @@
private string modalClass = "";
private bool showBackdrop = false;
public async Task OpenModal()
public async Task ShowAsync()
{
modalDisplay = "block;";
await Task.Delay(100);//Delay allows bootstrap to perform nice fade animation
@ -41,7 +41,7 @@
showBackdrop = true;
}
public async Task Close()
public async Task CloseAsync()
{
modalDisplay = "none";
await Task.Delay(250);//Delay allows bootstrap to perform nice fade animation

View File

@ -29,7 +29,6 @@
}
</tbody>
</table>
</div>
<ModalComponent @ref="modal">
@ -67,13 +66,13 @@
private async Task ConfirmDelete(Cocktail c)
{
SelectedCocktail = c;
await modal.OpenModal();
await modal.ShowAsync();
}
private async Task CloseDialog()
{
SelectedCocktail = null;
await modal.Close();
await modal.CloseAsync();
}
private async Task DeleteCocktail(MouseEventArgs e)
{

View File

@ -0,0 +1,147 @@
@page "/settings/glasses/edit"
@page "/settings/glasses/edit/{id}"
@using CocktailWeb.Data
@using Microsoft.AspNetCore.Components.Sections
@using Microsoft.EntityFrameworkCore
@using Microsoft.Extensions.Options
@inject IDbContextFactory<DbDataContext> DataContextFactory;
@inject NavigationManager nav;
@inject IWebHostEnvironment env;
@inject IOptions<GeneralSettings> Config;
<SectionContent SectionId="TopRow.Title">
<label>Glas bearbeiten</label>
</SectionContent>
<EditForm EditContext="editContext" OnValidSubmit="OnSubmit">
<div class="d-flex gap-3">
<div class="border border-2 rounded p-3 w-100">
<div class="mb-3">
<label class="form-label" for="name">Name (optional)</label>
<input class="form-control" id="name" name="name" type="text" @bind=@curGlas.Name />
</div>
<div class="mb-3">
<label class="form-label" for="menge">Füllmenge</label>
<div class="input-group">
<input class="form-control text-end" id="menge" name="menge" type="number" @bind=@curGlas.Fuellmenge />
<span class="input-group-text">ml</span>
<button type="button" class="btn btn-secondary" @onclick="() => ModifyAmount(-10)"><i class="bi bi-dash"></i></button>
<button type="button" class="btn btn-secondary" @onclick="() => ModifyAmount(10)"><i class="bi bi-plus"></i></button>
</div>
<div class="form-text"><ValidationMessage For="() => curGlas.Fuellmenge" /></div>
</div>
<button type="submit" name="submit" class="btn btn-primary">Speichern</button>
<button type="button" @onclick="@(() => nav.NavigateTo(PrevPageURL))" class="btn btn-secondary">Abbrechen</button>
</div>
<div class="border border-2 rounded p-3 w-100">
<div class="mb-3">
<label class="form-label" for="image">Bild</label>
<div class="mb-2">
@if (curGlas.ImageURL != null)
{
<img style="max-width:128px;" src="@curGlas.ImageURL" />
}
else
{
<div>Kein Bild vorhanden</div>
}
</div>
<label class="form-label" for="image">Neues Bild hochladen</label>
<InputFile OnChange="Bild_OnChange" class="form-control" id="image" name="image" accept=".jpg,.png,.jpeg,.gif,.webp" />
</div>
</div>
</div>
</EditForm>
@code {
[Parameter]
public string? id { get; set; }
public Glas curGlas = null!;
public IBrowserFile? NewImage;
private DbDataContext? _DataContext;
private string PrevPageURL = "/settings/glasses";
EditContext? editContext;
ValidationMessageStore? valMessages;
protected override async Task OnInitializedAsync()
{
if (id != null)
{
_DataContext ??= await DataContextFactory.CreateDbContextAsync();
if (_DataContext != null) curGlas = _DataContext.Glasses.Single(f => f.Id == Convert.ToInt32(id));
}
curGlas ??= new(); // Falls keine ID angegeben wurde oder der Eintrag in der Datenbank nicht gefunden wurde, gehen wir davon aus dass ein neuer Eintrag erstellt wird.
editContext = new(curGlas);
editContext.OnValidationRequested += editContext_OnValidationRequested;
valMessages = new(editContext);
}
private void Bild_OnChange(InputFileChangeEventArgs e)
{
NewImage = e.GetMultipleFiles().FirstOrDefault();
}
private void ModifyAmount(int amount)
{
curGlas.Fuellmenge = Math.Max(curGlas.Fuellmenge + amount, 0);
}
private void editContext_OnValidationRequested(object? sender, ValidationRequestedEventArgs args)
{
valMessages?.Clear();
if (curGlas.Fuellmenge <= 0) valMessages?.Add(() => curGlas.Fuellmenge, "Füllmenge muss größer 0 sein!");
}
private async Task OnSubmit()
{
_DataContext ??= await DataContextFactory.CreateDbContextAsync();
if (curGlas != null && _DataContext != null)
{
if (id != null)
{
_DataContext.Glasses.Update(curGlas);
}
else
{
_DataContext.Glasses.Add(curGlas);
}
await _DataContext.SaveChangesAsync();
if (NewImage != null)
{
try
{
// Bild hochladen
var relativeuploadpath = Path.Join(Config.Value.ImageUploadDir, $"glas_{curGlas.Id}{Path.GetExtension(NewImage.Name)}");
var fullpath = Path.Join(env.WebRootPath, relativeuploadpath);
string? folder = Path.GetDirectoryName(fullpath);
if (folder != null && !Path.Exists(folder)) Directory.CreateDirectory(folder);
Stream stream = NewImage.OpenReadStream(maxAllowedSize: Config.Value.MaxAllowedUploadSizeInMB * 1024 * 1024);
FileStream fs = File.Create(fullpath);
await stream.CopyToAsync(fs);
stream.Close();
fs.Close();
curGlas.ImageURL = relativeuploadpath;
// URL hinterlegen und wieder speichern
_DataContext.Glasses.Update(curGlas);
await _DataContext.SaveChangesAsync();
}
catch (Exception ex)
{
Console.WriteLine($"Error uploading image: {ex.Message}");
}
}
}
nav.NavigateTo(PrevPageURL);
}
}

View File

@ -1,10 +1,90 @@
@page "/settings/glasses"
@using CocktailWeb.Data
@using Microsoft.AspNetCore.Components.Sections
@using Microsoft.EntityFrameworkCore
@inject IDbContextFactory<DbDataContext> DataContextFactory
<SectionContent SectionId="TopRow.Title">
<label>Einstellungen - Gläser</label>
</SectionContent>
<a class="btn btn-primary mb-3" href="/settings/glasses/edit">Glas hinzufügen</a>
<div class="table-responsive">
<table class="table table-striped table-hover table-bordered table-dark border-dark">
<tbody>
@foreach (Glas g in GlassList)
{
<tr>
<td class="p-0" style="width:64px"><img src="@g.ImageURL" style="max-width:100%; max-height:auto;" /></td>
<td style="vertical-align:middle;">@g.DisplayName</td>
<td style="text-align:right; vertical-align:middle;">
<a class="btn btn-primary" href="/settings/glasses/edit/@g.Id">Bearbeiten</a>
<button name="submit" type="submit" class="btn btn-outline-danger" @onclick="() => ConfirmDeleteAsync(g)">Löschen</button>
</td>
</tr>
}
</tbody>
</table>
</div>
<ModalComponent @ref="modal">
<Title>Löschen bestätigen</Title>
<Body>
Willst du das Glas wirklich löschen?
</Body>
<Footer>
<button class="btn btn-danger" @onclick="DeleteGlassAsync">Jo</button>
<button class="btn btn-primary" @onclick="CloseDialogAsync">Nee</button>
</Footer>
</ModalComponent>
@code {
private List<Glas> GlassList = new();
private DbDataContext? _DataContext;
private ModalComponent modal = null!;
private Glas? SelectedGlas;
protected override async Task OnInitializedAsync()
{
await ShowGlassesAsync();
}
private async Task ShowGlassesAsync()
{
_DataContext ??= await DataContextFactory.CreateDbContextAsync();
if (_DataContext != null)
{
GlassList = _DataContext.Glasses.OrderBy(g => g.Fuellmenge).ToList();
}
}
private async Task ConfirmDeleteAsync(Glas g)
{
SelectedGlas = g;
await modal.ShowAsync();
}
private async Task DeleteGlassAsync()
{
if (SelectedGlas == null) return;
_DataContext ??= await DataContextFactory.CreateDbContextAsync();
if (_DataContext != null)
{
_DataContext.Glasses.Remove(SelectedGlas);
await _DataContext.SaveChangesAsync();
await ShowGlassesAsync();
}
await CloseDialogAsync();
}
private async Task CloseDialogAsync()
{
SelectedGlas = null;
await modal.CloseAsync();
}
}

View File

@ -105,12 +105,12 @@
if (CocktailsWithIngredient.Count > 0)
{
InfoText = String.Join(", ", CocktailsWithIngredient.Select(c => c.Name).ToArray());
await dlgInfo.OpenModal();
await dlgInfo.ShowAsync();
}
else
{
SelectedIngredient = fl;
await dlgDelete.OpenModal();
await dlgDelete.ShowAsync();
}
}
@ -133,6 +133,6 @@
private async Task CloseDialog(ModalComponent dlg)
{
SelectedIngredient = null;
await dlg.Close();
await dlg.CloseAsync();
}
}

View File

@ -35,7 +35,7 @@ namespace CocktailWeb.Pages.Settings
{
SelectedFiller = f;
SelectedFlasche = f.Flasche;
await modal.OpenModal();
await modal.ShowAsync();
}
@ -63,7 +63,7 @@ namespace CocktailWeb.Pages.Settings
{
SelectedFiller = null;
SelectedFlasche = null;
await modal.Close();
await modal.CloseAsync();
}
}
}

View File

@ -104,14 +104,14 @@
private async Task OpenDialog()
{
await Pwd_Dialog.OpenModal();
await Pwd_Dialog.ShowAsync();
}
private async Task CloseDialog()
{
Pwd_ErrorText = null;
Pwd_inputPassword = null;
await Pwd_Dialog.Close();
await Pwd_Dialog.CloseAsync();
}