KoogleApp/src/Koogle.Web/Components/Game/Training/TrainingBoard.razor

240 lines
8.2 KiB
Plaintext

@using Fluxor
@using Koogle.Application.DTOs
@using Koogle.Application.Games
@using Koogle.Application.Games.Training
@using Koogle.Web.Store.GameState
@using Koogle.Web.Store.DayState
@using MudBlazor
@inherits Fluxor.Blazor.Web.Components.FluxorComponent
@implements IDisposable
@inject IState<GameState> GameState
@inject IState<DayState> DayState
<MudPaper Class="pa-4">
@* <MudText Typo="Typo.h6" Class="mb-4">
<MudIcon Icon="@Icons.Material.Filled.TableChart" Class="mr-2" />
Training - Tafel
</MudText> *@
@if (_playerStats.Count == 0)
{
<MudAlert Severity="Severity.Info">
Noch keine Statistiken vorhanden. Starte mit dem Werfen!
</MudAlert>
}
else
{
<MudTable Items="@_playerStats"
Dense="true"
Hover="true"
Striped="true"
Bordered="true"
Class="mb-4">
<HeaderContent>
<MudTh>Spieler</MudTh>
<MudTh Style="text-align: right">Würfe</MudTh>
<MudTh Style="text-align: right">Kegel</MudTh>
<MudTh Style="text-align: right">Abgeräumt</MudTh>
<MudTh Style="text-align: right">Kränze</MudTh>
<MudTh Style="text-align: right">alle 9</MudTh>
<MudTh Style="text-align: right">Gossen</MudTh>
<MudTh Style="text-align: right">Glocke</MudTh>
<MudTh Style="text-align: right">⌀</MudTh>
</HeaderContent>
<RowTemplate>
<MudTd>
@if (context.IsCurrentPlayer)
{
<MudBadge Color="Color.Primary" Dot="true" Overlap="false"
Icon=@Icons.Material.Filled.ArrowCircleDown
Origin="Origin.TopLeft">
<MudText Typo="Typo.body1" Style="font-weight: 600">
@context.PlayerName
</MudText>
</MudBadge>
}
else
{
<MudText Typo="Typo.body1">@context.PlayerName</MudText>
}
</MudTd>
<MudTd Style="text-align: right">@context.ThrowCount</MudTd>
<MudTd Style="text-align: right">@context.PinCount</MudTd>
<MudTd Style="text-align: right">@context.ClearedCount</MudTd>
<MudTd Style="text-align: right">
@if (context.CircleCount > 0)
{
<MudChip T="string" Size="Size.Small" Color="Color.Success" Variant="Variant.Filled">
@context.CircleCount
</MudChip>
}
else
{
<span>0</span>
}
</MudTd>
<MudTd Style="text-align: right">
@if (context.StrikeCount > 0)
{
<MudChip T="string" Size="Size.Small" Color="Color.Warning" Variant="Variant.Filled">
@context.StrikeCount
</MudChip>
}
else
{
<span>0</span>
}
</MudTd>
<MudTd Style="text-align: right">
@if (context.GutterCount > 0)
{
<MudChip T="string" Size="Size.Small" Color="Color.Error" Variant="Variant.Filled">
@context.GutterCount
</MudChip>
}
else
{
<span>0</span>
}
</MudTd>
<MudTd Style="text-align: right">
@if (context.BellCount > 0)
{
<MudChip T="string" Size="Size.Small" Color="Color.Info" Variant="Variant.Filled">
@context.BellCount
</MudChip>
}
else
{
<span>0</span>
}
</MudTd>
<MudTd Style="text-align: right; font-weight: 600">
@context.Average.ToString("F1")
</MudTd>
</RowTemplate>
</MudTable>
@* Summary row *@
<MudPaper Class="pa-3 mt-4" Elevation="0" Style="background-color: var(--mud-palette-background-grey);">
<MudStack Row="true" Justify="Justify.SpaceBetween">
<MudText Typo="Typo.body2">
<strong>Gesamt:</strong> @_totalThrows Würfe, @_totalPins Kegel
</MudText>
<MudText Typo="Typo.body2">
<strong>Team-⌀:</strong> @_teamAverage.ToString("F2")
</MudText>
</MudStack>
</MudPaper>
}
</MudPaper>
@code {
private List<PlayerStatsRow> _playerStats = [];
private int _totalThrows;
private int _totalPins;
private double _teamAverage;
protected override void OnInitialized()
{
base.OnInitialized();
GameState.StateChanged += OnGameStateChanged;
UpdateStats();
}
private void OnGameStateChanged(object? sender, EventArgs e)
{
UpdateStats();
InvokeAsync(StateHasChanged);
}
private void UpdateStats()
{
_playerStats.Clear();
_totalThrows = 0;
_totalPins = 0;
var gameState = GameState.Value;
if (gameState.GameModel is not TrainingGameModel model)
{
// Try to deserialize if it's a JsonElement
if (gameState.GameModel is System.Text.Json.JsonElement jsonElement)
{
try
{
model = System.Text.Json.JsonSerializer.Deserialize<TrainingGameModel>(
jsonElement.GetRawText(),
GameModelFactory.JsonSerializerOptions);
}
catch
{
return;
}
}
else
{
return;
}
}
if (model?.PlayerStatistics == null)
{
return;
}
var currentPlayerId = gameState.Participants.CurrentPlayerId;
var persons = DayState.Value.AvailablePersons;
foreach (var (playerId, stats) in model.PlayerStatistics)
{
var person = persons.FirstOrDefault(p => p.Id == playerId);
var playerName = person?.Name ?? "Unbekannt";
_playerStats.Add(new PlayerStatsRow
{
PlayerId = playerId,
PlayerName = playerName,
ThrowCount = stats.ThrowCount,
ClearedCount = stats.ClearedCount,
PinCount = stats.PinCount,
CircleCount = stats.CircleCount,
StrikeCount = stats.StrikeCount,
GutterCount = stats.GutterCount,
BellCount = stats.BellCount,
Average = stats.Average,
IsCurrentPlayer = playerId == currentPlayerId
});
_totalThrows += stats.ThrowCount;
_totalPins += stats.PinCount;
}
// Sort by pin count descending (best player first)
_playerStats = _playerStats.OrderByDescending(p => p.PinCount).ToList();
_teamAverage = _totalThrows > 0 ? (double)_totalPins / _totalThrows : 0;
}
public void Dispose()
{
GameState.StateChanged -= OnGameStateChanged;
}
private record PlayerStatsRow
{
public Guid PlayerId { get; init; }
public string PlayerName { get; init; } = "";
public int ThrowCount { get; init; }
public int ClearedCount { get; init; }
public int PinCount { get; init; }
public int CircleCount { get; init; }
public int StrikeCount { get; init; }
public int GutterCount { get; init; }
public int BellCount { get; init; }
public double Average { get; init; }
public bool IsCurrentPlayer { get; init; }
}
}