cocktailweb/CocktailWeb/Pages/CocktailView.razor

310 lines
16 KiB
Plaintext

@page "/cocktails/{CocktailId}"
@using CocktailWeb.Data
@using Microsoft.AspNetCore.Components.Sections
@using Microsoft.EntityFrameworkCore
@inject IDbContextFactory<DbDataContext> DataContextFactory;
<SectionContent SectionId="TopRow.Title">
<a class="btn btn-primary" href="/cocktails">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-left-circle" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M1 8a7 7 0 1 0 14 0A7 7 0 0 0 1 8m15 0A8 8 0 1 1 0 8a8 8 0 0 1 16 0m-4.5-.5a.5.5 0 0 1 0 1H5.707l2.147 2.146a.5.5 0 0 1-.708.708l-3-3a.5.5 0 0 1 0-.708l3-3a.5.5 0 1 1 .708.708L5.707 7.5z" />
</svg>
Zurück
</a>
</SectionContent>
@if (SelectedCocktail == null)
{
<h3>Cocktail konnte nicht gefunden werden</h3>
}
else
{
<div class="d-flex gap-3">
<div class="card mb-3 w-100">
<div class="row g-0">
<div class="col-md-8">
<div class="card-body">
<h5 class="card-title">Einstellungen</h5>
<p class="card-text">
<h6>
Stärke
</h6>
@if (!UseNewIntensityCalc)
{
<div class="btn-group" role="group">
<button @onclick="() => SetIntensity(-60)" class="btn @(SelectedCocktail.IsAlcoholic ? "" : "disabled") btn-@(DrinkIntensity <= -60 ? "" : "outline-")success"><i class="bi bi-peace fs-5"></i></button>
<button @onclick="() => SetIntensity(-40)" class="btn @(SelectedCocktail.IsAlcoholic ? "" : "disabled") btn-@(DrinkIntensity <= -40 ? "" : "outline-")success"><i class="bi bi-dash fs-5"></i></button>
<button @onclick="() => SetIntensity(-20)" class="btn @(SelectedCocktail.IsAlcoholic ? "" : "disabled") btn-@(DrinkIntensity <= -20 ? "" : "outline-")success"><i class="bi bi-dash"></i></button>
<button @onclick="() => SetIntensity(0)" class="btn @(SelectedCocktail.IsAlcoholic ? "" : "disabled") btn-@(DrinkIntensity == 0 ? "" : "")warning"><i class="bi bi-circle"></i></button>
<button @onclick="() => SetIntensity(20)" class="btn @(SelectedCocktail.IsAlcoholic ? "" : "disabled") btn-@(DrinkIntensity >= 20 ? "" : "outline-")danger"><i class="bi bi-plus"></i></button>
<button @onclick="() => SetIntensity(40)" class="btn @(SelectedCocktail.IsAlcoholic ? "" : "disabled") btn-@(DrinkIntensity >= 40 ? "" : "outline-")danger"><i class="bi bi-plus fs-5"></i></button>
<button @onclick="() => SetIntensity(60)" class="btn @(SelectedCocktail.IsAlcoholic ? "" : "disabled") btn-@(DrinkIntensity >= 60 ? "" : "outline-")danger"><i class="bi bi-radioactive fs-5"></i></button>
</div>
}
else
{
<div class="btn-group" role="group">
<button @onclick="() => SetIntensityPercentual(-3)" class="btn @(SelectedCocktail.IsAlcoholic ? "" : "disabled") btn-@(DrinkIntensity <= -3 ? "" : "outline-")success"><i class="bi bi-peace fs-5"></i></button>
<button @onclick="() => SetIntensityPercentual(-2)" class="btn @(SelectedCocktail.IsAlcoholic ? "" : "disabled") btn-@(DrinkIntensity <= -2 ? "" : "outline-")success"><i class="bi bi-dash fs-5"></i></button>
<button @onclick="() => SetIntensityPercentual(-1)" class="btn @(SelectedCocktail.IsAlcoholic ? "" : "disabled") btn-@(DrinkIntensity <= -1 ? "" : "outline-")success"><i class="bi bi-dash"></i></button>
<button @onclick="() => SetIntensityPercentual(0)" class="btn @(SelectedCocktail.IsAlcoholic ? "" : "disabled") btn-@(DrinkIntensity == 0 ? "" : "")warning"><i class="bi bi-circle"></i></button>
<button @onclick="() => SetIntensityPercentual(1)" class="btn @(SelectedCocktail.IsAlcoholic ? "" : "disabled") btn-@(DrinkIntensity >= 1 ? "" : "outline-")danger"><i class="bi bi-plus"></i></button>
<button @onclick="() => SetIntensityPercentual(2)" class="btn @(SelectedCocktail.IsAlcoholic ? "" : "disabled") btn-@(DrinkIntensity >= 2 ? "" : "outline-")danger"><i class="bi bi-plus fs-5"></i></button>
<button @onclick="() => SetIntensityPercentual(3)" class="btn @(SelectedCocktail.IsAlcoholic ? "" : "disabled") btn-@(DrinkIntensity >= 3 ? "" : "outline-")danger"><i class="bi bi-radioactive fs-5"></i></button>
</div>
}
</p>
@if (ErrorMessage != null)
{
<div class="alert alert-danger" role="alert">
@ErrorMessage
</div>
}
@if (CocktailCode != null)
{
<div class="alert alert-dark" style="white-space: pre-line" role="alert">
@CocktailCode
</div>
}
<button class="btn btn-primary" @onclick=CreateCocktailCode>Lets goooooo!</button>
</div>
</div>
</div>
</div>
<div class="card mb-3 w-100">
<div class="row g-0">
<div class="col-md-4">
<img src="@SelectedCocktail.ImageURL" class="img-fluid rounded-start" alt="...">
</div>
<div class="col-md-8">
<div class="card-body">
<h5 class="card-title">@SelectedCocktail.Name</h5>
<p class="card-text">
<h6>Rezept:</h6>
<table class="table-primary table-borderless w-100">
@{
int i = 1;
}
@foreach (var Zutat in SelectedCocktail.Cocktailflaschen.OrderBy(f => f.Reihenfolge))
{
<tr class="@(ZutatInMaschine(Zutat) ? "" : "text-danger")">
<td>@i.</td>
<td>@Zutat.Flasche?.Name</td>
<td class="text-end">@Zutat.Menge ml</td>
@if (DrinkIntensity != 0)
{
<td>=></td>
<td class="text-end">@ModifiedCocktail?.Cocktailflaschen.First(cf => cf.FlascheID == Zutat.FlascheID).Menge ml</td>
}
<td class="text-end">@(ZutatInMaschine(Zutat) ? "" : "fehlt")</td>
</tr>
i++;
}
<tr>
<td></td>
<td>Gesamt</td>
<td class="text-end">@SelectedCocktail.Cocktailflaschen.Sum(cf => cf.Menge) ml</td>
@if (DrinkIntensity != 0)
{
<td>=></td>
<td class="text-end">@ModifiedCocktail?.Cocktailflaschen.Sum(cf => cf.Menge) ml</td>
}
<td class="text-end"></td>
</tr>
</table>
</p>
</div>
</div>
</div>
</div>
</div>
}
@code {
[Parameter]
public string? CocktailId { get; set; }
private DbDataContext? _DataContext;
private Cocktail? SelectedCocktail;
private Cocktail? ModifiedCocktail;
private List<Filler>? MaschinenFiller;
//private List<CocktailFlasche> ModifiedCocktailRecipe = new();
private int DrinkIntensity = 0;
private bool UseNewIntensityCalc = false;
private string? ErrorMessage;
private string? CocktailCode;
protected override async Task OnInitializedAsync()
{
int id = Convert.ToInt32(CocktailId);
//Staerke_Off.Add();
_DataContext ??= await DataContextFactory.CreateDbContextAsync();
if (_DataContext != null)
{
SelectedCocktail = _DataContext.Cocktails.Include(c => c.Cocktailflaschen).ThenInclude(cf => cf.Flasche).Single(c => c.Id == id);
ModifiedCocktail = _DataContext.Cocktails.Include(c => c.Cocktailflaschen).ThenInclude(cf => cf.Flasche).AsNoTracking().Single(c => c.Id == id);
MaschinenFiller = _DataContext.Fillers.Include(f => f.Flasche).OrderBy(f => f.Pos).ToList();
}
// if (SelectedCocktail != null)
// {
// foreach (CocktailFlasche cf in SelectedCocktail.Cocktailflaschen)
// {
// ModifiedCocktailRecipe.Add(new CocktailFlasche() {
// Flasche = cf.Flasche,
// Menge = cf.Menge
// });
// }
// }
}
private bool ZutatInMaschine(CocktailFlasche zutat)
{
return (MaschinenFiller != null && MaschinenFiller.Exists(f => f.Flasche == zutat.Flasche));
}
/// <summary>
/// Prüft, ob der Cocktail gesendet werden kann
/// </summary>
/// <returns></returns>
private bool IsValid()
{
ErrorMessage = null;
if (ModifiedCocktail == null || MaschinenFiller == null)
{
ErrorMessage = "Cocktail nicht gefunden.";
return false;
}
if (ModifiedCocktail.Cocktailflaschen.Count == 0)
{
ErrorMessage = "Der Cocktail enthält keine Zutaten";
return false;
}
if (!ModifiedCocktail.Cocktailflaschen.All(cf => MaschinenFiller.Any(mf => mf.Flasche?.Id == cf.FlascheID)))
{
ErrorMessage = "Es sind nicht alle Zutaten in der Cocktailmaschine geladen!";
return false;
}
return true;
}
/// <summary>
/// Erstellt den für die Arduino-Steuerung erforderlichen Code
/// </summary>
private void CreateCocktailCode()
{
CocktailCode = null;
if (!IsValid() || ModifiedCocktail == null || MaschinenFiller == null) return;
List<string> lines = new();
lines.Add("START");
@foreach (CocktailFlasche Zutat in ModifiedCocktail.Cocktailflaschen.OrderBy(f => f.Reihenfolge))
{
string line = "";
Filler Filler = MaschinenFiller.First(mf => mf.Flasche?.Id == Zutat.FlascheID);
if (Filler.Type == Filler.FillerType.Pump)
{
line = $"P{Filler.Pos}={Zutat.Menge}";
}
else if (Filler.Type == Filler.FillerType.Pourer)
{
line = $"F{Filler.Pos}={Zutat.Menge}";
}
lines.Add(line);
}
lines.Add("ZIEL");
CocktailCode = String.Join("\r\n", lines.ToArray());
}
/// <summary>
/// Setzt die Alkoholintensität und berechnet die Mengen für ModifiedCocktail entsprechend neu
/// </summary>
/// <param name="intensity">Zugabe/Abzug von Alkohol in Prozent</param>
private void SetIntensity(int intensity)
{
DrinkIntensity = intensity;
if (ModifiedCocktail == null || SelectedCocktail == null) return;
foreach (CocktailFlasche cf in ModifiedCocktail.Cocktailflaschen)
{
int OriginalMenge = SelectedCocktail.Cocktailflaschen.First(scf => scf.Id == cf.Id).Menge;
if (cf.Flasche.Alkoholisch)
{
cf.Menge = OriginalMenge + (OriginalMenge * intensity / 100);
}
else
{
cf.Menge = OriginalMenge - (OriginalMenge * intensity / 100);
}
}
// Durch das anteilige Umrechnen ändert sich die Gesamtmenge, daher passen wir die Mengen nochmal an
int AktGesMenge = ModifiedCocktail.Cocktailflaschen.Sum(cf => cf.Menge);
int OrigMenge = SelectedCocktail.Cocktailflaschen.Sum(cf => cf.Menge);
foreach (CocktailFlasche cf in ModifiedCocktail.Cocktailflaschen)
{
cf.Menge = (int)((float)cf.Menge / AktGesMenge * OrigMenge);
}
}
// ToDo: Ggf. noch Rundungsfehler drin oder wirklich noch grobe Fehler in der Mathematik.. Gesamtmenge passt irgendwie nicht.
/// <summary>
/// Ändert die Alkoholintensität basierend auf den Prozentwerten anstatt der Menge
/// </summary>
/// <param name="intensitylevel">Intensitätslevel (z.B. -1, 0, 1,2 ...)</param>
private void SetIntensityPercentual(int intensitylevel)
{
DrinkIntensity = intensitylevel;
if (ModifiedCocktail == null || SelectedCocktail == null) return;
int DivideParts = 4; // Gibt an, in wieviele Teile die nicht-alkoholische Gesamtmenge aufgeteilt wird. Sollte mindestens 1 oder 2 mehr als das Max.Intensitätslevel sein
float IncreasePerLevel_pct; // Gibt an, um welchen Anteil in % die alkoholischen Getränke steigen.
float SumAlcoholic_ml = SelectedCocktail.Cocktailflaschen.Where(cf => cf.Flasche.Alkoholisch).Sum(cf => cf.Menge); // Summe in ml der Alkoholhaltigen Zutaten
float SumNonAlcoholic_ml = SelectedCocktail.Cocktailflaschen.Where(cf => !cf.Flasche.Alkoholisch).Sum(cf => cf.Menge); // Summe in ml der Alkoholfreien Zutaten
float SumTotal = SumAlcoholic_ml + SumNonAlcoholic_ml;
float SumAlcoholic_pct = SumAlcoholic_ml / SumTotal * 100; //Prozentwert an alkoholhaltigen Zutaten
float SumNonAlcoholic_pct = SumNonAlcoholic_ml / SumTotal * 100; //Prozentwert an alkoholhaltigen Zutaten
float SumBasis_ml = intensitylevel >= 0 ? SumNonAlcoholic_ml : SumAlcoholic_ml; // Wenn Intensität > 0, dann ist Summenbasis nichtalkoholisch, ansonsten alkoholisch
if (intensitylevel >= 0)
{
/// Wenn alkoholhaltiges 30% ausmacht, teilen wir den Rest (alkoholfreis, 70%) durch die o.g. DivideParts, damit wir wissen um wieviel Prozent pro Stufe wir erhöhen können
IncreasePerLevel_pct = SumNonAlcoholic_pct / DivideParts;
}
else
{
// Cocktail abschwächen, daher teilen wir in die andere Richtung auf
IncreasePerLevel_pct = SumAlcoholic_pct / DivideParts;
}
foreach (CocktailFlasche cf in ModifiedCocktail.Cocktailflaschen)
{
float OrigMenge = SelectedCocktail.Cocktailflaschen.First(f => f.Id == cf.Id).Menge;
// Herausfinden, wieviel Prozent die Zutat in ihrem Bereich (Alkoholisch/Nichtalkoholisch) ausmacht
float ZutatIncrease_pct = IncreasePerLevel_pct / SumBasis_ml * cf.Menge;
float ZutatMenge_pct = (float)OrigMenge / SumTotal * 100;
// Neue Menge in Prozent: ZutatMenge_pct + ZutatIncrease_pct
if (!cf.Flasche.Alkoholisch ^ intensitylevel < 0 )
{
ZutatIncrease_pct *= -1;
}
cf.Menge = (int)Math.Round(OrigMenge / ZutatMenge_pct * (ZutatMenge_pct + (ZutatIncrease_pct * intensitylevel)), 0, MidpointRounding.AwayFromZero);
}
}
}