dev daystate

This commit is contained in:
beo3000 2025-11-17 18:48:54 +01:00
parent 1026ac79f7
commit b8986818b7
13 changed files with 274 additions and 59 deletions

View File

@ -15,8 +15,8 @@
@foreach (var day in DaysState.Value.Days) @foreach (var day in DaysState.Value.Days)
{ {
<MudListItem Text="@day.Date.ToShortDateString()" <MudListItem Text="@(GetDayStr(day))"
OnClick="OnClick" OnClick="@(() => OnClick(day))"
Value="@day" /> Value="@day" />
} }
@ -26,6 +26,11 @@
@code { @code {
private DayState _selectedValue; private DayState _selectedValue;
private string GetDayStr(DayState day)
{
return $"{day.Date.ToShortDateString()} - {day.Status}/{(int)day.Status} ({day.Id}), (P:{day.PlayerIds.Select(_ => _.ToString()).Aggregate((a, b) => $"{a},{b}")})";
}
public DayState? SelectedValue public DayState? SelectedValue
{ {
get => _selectedValue; get => _selectedValue;
@ -34,7 +39,7 @@
protected override void OnInitialized() protected override void OnInitialized()
{ {
if (DaysState.Value.Loaded) if (!DaysState.Value.Loaded)
{ {
Dispatcher.Dispatch(new LoadDaysAction()); Dispatcher.Dispatch(new LoadDaysAction());
} }
@ -42,9 +47,9 @@
base.OnInitialized(); base.OnInitialized();
} }
private void OnClick(MouseEventArgs obj) private void OnClick(DayState dayState)
{ {
Dispatcher.Dispatch(new ChangeSelectedDay(dayState));
} }
} }

View File

@ -2,6 +2,7 @@
@using KoogleApp.Model @using KoogleApp.Model
@using KoogleApp.Model.EventMessages @using KoogleApp.Model.EventMessages
@using KoogleApp.Services; @using KoogleApp.Services;
@using KoogleApp.Store.DayFeature
@using KoogleApp.Store.Player @using KoogleApp.Store.Player
@inherits FluxorComponent @inherits FluxorComponent
@ -9,6 +10,8 @@
@inject IDispatcher Dispatcher @inject IDispatcher Dispatcher
@* @inject IState<PlayersState> PlayersState *@ @* @inject IState<PlayersState> PlayersState *@
@inject IState<PlayerState> PlayerState @inject IState<PlayerState> PlayerState
@inject IState<DayState> DayState
@inject IState<DaysState> DaysState
@if (@PlayerState.Value != null) @if (@PlayerState.Value != null)
{ {
@ -17,11 +20,14 @@
<MudItem xs="12"> <MudItem xs="12">
<MudPaper Class="d-flex align-center justify-center mud-width-full py-0"> <MudPaper Class="d-flex align-center justify-center mud-width-full py-0">
<MudText Typo="Typo.h4">@PlayerState.Value.Name</MudText> <MudText Typo="Typo.h4">@PlayerState.Value.Name</MudText>
@if (DayState.Value.Status == DayStatus.Started)
{
<StateSwitch TState="PlayerState" <StateSwitch TState="PlayerState"
Color="Color.Tertiary" Color="Color.Tertiary"
ValueSelector="@(state => state.Available)" ValueSelector="@(state => state.Available)"
OnValueChanged="@(value => Dispatcher.Dispatch(new ChangePlayerAvailableAction(PlayerState.Value.Id, value)))" /> OnValueChanged="@(value => Dispatcher.Dispatch(new ChangePlayerAvailableAction(PlayerState.Value.Id, value, DayState.Value, DaysState.Value)))" />
<MudText Typo="Typo.subtitle2">@(PlayerState.Value.Available ? "anwesend" : "abwesend")</MudText> <MudText Typo="Typo.subtitle2">@(PlayerState.Value.Available ? "anwesend" : "abwesend")</MudText>
}
</MudPaper> </MudPaper>
</MudItem> </MudItem>

View File

@ -9,6 +9,7 @@
@inject IDispatcher Dispatcher @inject IDispatcher Dispatcher
@inject IState<UndoRedoState> UndoRedoState @inject IState<UndoRedoState> UndoRedoState
@inject IState<ThrowPanelState> ThrowPanelState @inject IState<ThrowPanelState> ThrowPanelState
@inject IState<DayState> DayState
@inject IDialogService DialogService @inject IDialogService DialogService
<MudTooltip Text="Undo" Color="Color.Primary" Placement="Placement.Bottom" Arrow="true"> <MudTooltip Text="Undo" Color="Color.Primary" Placement="Placement.Bottom" Arrow="true">
@ -67,7 +68,7 @@
} }
else else
{ {
var result = await DialogService.ShowMessageBox("Spiel beenden?", "Spiel wirklich abbrechen?", "JA", "NEIN"); var result = await DialogService.ShowMessageBox("Spiel beenden?", "Spiel wirklich abbrechen?", "JA", "NEIN", cancelText: "Abbrechen");
if (result.Value) if (result.Value)
{ {
var action = new StartStopAction(ThrowPanelState.Value, null); var action = new StartStopAction(ThrowPanelState.Value, null);
@ -82,9 +83,15 @@
// await InvokeAsync(StateHasChanged); // await InvokeAsync(StateHasChanged);
} }
private void CloseDayClick(MouseEventArgs obj) private async Task CloseDayClick(MouseEventArgs obj)
{ {
Dispatcher.Dispatch(new CloseDayStateAction()); var result = await DialogService.ShowMessageBox("Spiel Abschließen?", "Spiel wirklich abbrechen?", "JA abschließen", "NEIN offen lassen", cancelText: "Abbrechen");
if (!result.HasValue)
{
return;
}
Dispatcher.Dispatch(new ChangeDayStatusAction(DayState.Value, result.Value ? DayStatus.Closed : DayStatus.Postponed));
} }
} }

View File

@ -36,6 +36,7 @@
{ {
case GameView.Throw: case GameView.Throw:
<PanelToolbar> <PanelToolbar>
@GetDayStr()
@if (DayState.Value.Status != DayStatus.Started) @if (DayState.Value.Status != DayStatus.Started)
{ {
<DayListMenu/> <DayListMenu/>
@ -60,6 +61,7 @@
<!-- Scrollbarer Inhalt --> <!-- Scrollbarer Inhalt -->
<MudContainer Class="mt-4"> <MudContainer Class="mt-4">
<p>@GetDayStr()</p>
@switch (_gameView) @switch (_gameView)
{ {
case GameView.Throw: case GameView.Throw:
@ -71,6 +73,7 @@
{ {
<ThrowPanel/> <ThrowPanel/>
} }
break; break;
case GameView.Board: case GameView.Board:
<BoardPanel/> <BoardPanel/>
@ -117,6 +120,22 @@
} }
} }
private string GetDayStr()
{
if (DayState.Value == null)
{
return "";
}
var day = DayState.Value;
var res = $"{day.Date.ToShortDateString()} - {day.Status}/{(int)day.Status} ({day.Id})";
if (day.PlayerIds.Length > 0)
{
res += $" (P:{day.PlayerIds.Select(_ => _.ToString()).Aggregate((a, b) => $"{a},{b}")})";
}
return res;
}
protected override async Task OnInitializedAsync() protected override async Task OnInitializedAsync()
{ {
await base.OnInitializedAsync(); await base.OnInitializedAsync();

View File

@ -8,6 +8,7 @@ namespace KoogleApp.Data.Repository
Task<List<Day>> GetAllAsync(int year); Task<List<Day>> GetAllAsync(int year);
Task<Day?> GetActiveDayAsync(); Task<Day?> GetActiveDayAsync();
Task<Day> AddAsync(Day day); Task<Day> AddAsync(Day day);
Task<Day> UpdateAsync(Day day);
} }
public class DayRepository(IDbContextFactory<AppDbContext> contextFactory, ILogger<IDayRepository> logger) public class DayRepository(IDbContextFactory<AppDbContext> contextFactory, ILogger<IDayRepository> logger)
@ -36,5 +37,13 @@ namespace KoogleApp.Data.Repository
await context.SaveChangesAsync(); await context.SaveChangesAsync();
return day; return day;
} }
public async Task<Day> UpdateAsync(Day day)
{
await using var context = await contextFactory.CreateDbContextAsync();
var res = context.Days.Update(day);
await context.SaveChangesAsync();
return res.Entity;
}
} }
} }

View File

@ -186,5 +186,11 @@ namespace KoogleApp.Data
var newDay = await _dayRepository.AddAsync(day); var newDay = await _dayRepository.AddAsync(day);
return newDay; return newDay;
} }
public async Task<Day> UpdateDayAsync(Day day)
{
var modifiedDay = await _dayRepository.UpdateAsync(day);
return modifiedDay;
}
} }
} }

View File

@ -8,22 +8,25 @@ namespace KoogleApp.Store.DayFeature
public record LoadDaysAction(); public record LoadDaysAction();
public record DayStateLoadedAction(Day Day); public record DayLoadedAction(Day Day);
public record DayStateLoadedAction(DayState DayState);
public record DaysStateLoadedAction(List<Day> Days, int Year); public record DaysStateLoadedAction(List<Day> Days, int Year);
public record AddDayStateAction(DayModel DayModel); //public record AddDayStateAction(DayModel DayModel);
public record ChangeSelectedDay(DayState DayState);
public record CloseDayStateAction(); public record ChangeDayStatusAction(DayState DayState, DayStatus Status);
public class DayModelSubmitSuccessAction { } public record DayModelSubmitSuccessAction(Day Day) { }
public class DayModelSubmitFailureAction(string errorMessage) public record DayModelSubmitFailureAction(string errorMessage)
{ {
public string ErrorMessage { get; } = errorMessage; public string ErrorMessage { get; } = errorMessage;
} }
public class DayModelSubmitAction(DayModel dayModel) public record DayModelSubmitAction(DayModel dayModel)
{ {
public DayModel DayModel { get; } = dayModel; public DayModel DayModel { get; } = dayModel;
} }

View File

@ -2,6 +2,7 @@
using Fluxor.Blazor.Web; using Fluxor.Blazor.Web;
using KoogleApp.Data; using KoogleApp.Data;
using KoogleApp.Model; using KoogleApp.Model;
using KoogleApp.Store.Player;
using System.Net.Http; using System.Net.Http;
using System.Runtime.InteropServices.JavaScript; using System.Runtime.InteropServices.JavaScript;
using System.Text.Json; using System.Text.Json;
@ -16,7 +17,7 @@ namespace KoogleApp.Store.DayFeature
var day = await dataService.GetActiveDayAsync(); var day = await dataService.GetActiveDayAsync();
if (day != null) if (day != null)
{ {
dispatcher.Dispatch(new DayStateLoadedAction(day)); dispatcher.Dispatch(new DayLoadedAction(day));
} }
} }
@ -31,20 +32,67 @@ namespace KoogleApp.Store.DayFeature
} }
} }
[EffectMethod]
public async Task HandelChangeDayStateAction(ChangeDayStatusAction action, IDispatcher dispatcher)
{
var day = DayStateSelector.DbConvert(action.DayState);
day.Status = action.Status;
await dataService.UpdateDayAsync(day);
}
[EffectMethod]
public async Task HandelChangeSelectedDay(ChangeSelectedDay action, IDispatcher dispatcher)
{
var day = DayStateSelector.DbConvert(action.DayState);
day.Status = DayStatus.Started;
await dataService.UpdateDayAsync(day);
}
[EffectMethod]
public async Task HandelChangePlayerAvailableAction(ChangePlayerAvailableAction action, IDispatcher dispatcher)
{
var newList = new List<int>(action.DayState.PlayerIds); // Kopie erstellen
if (action.IsAvailable)
{
newList.Add(action.PlayerId);
}
else
{
newList.Remove(action.PlayerId);
}
var day = DayStateSelector.DbConvert(action.DayState);
day.Players = JsonSerializer.Serialize(newList);
await dataService.UpdateDayAsync(day);
// Update an DayState senden
dispatcher.Dispatch(new DayStateLoadedAction(DayStateSelector.DbConvert(day)));
var newDays = new List<Day>(action.DaysState.Days.Select(_ => DayStateSelector.DbConvert(_)));
var idx = newDays.FindIndex(p => p.Id == action.DayState.Id);
newDays[idx].Players = day.Players;
// Update an DaysState senden
dispatcher.Dispatch(new DaysStateLoadedAction(newDays, action.DaysState.Year));
}
[EffectMethod] [EffectMethod]
public async Task SubmitDayModel(DayModelSubmitAction action, IDispatcher dispatcher) public async Task SubmitDayModel(DayModelSubmitAction action, IDispatcher dispatcher)
{ {
var msg = ""; var msg = "";
Day? day = null;
try try
{ {
var day = await dataService.AddDayAsync(new Day day = await dataService.AddDayAsync(new Day
{ {
Status = DayStatus.Started, Status = DayStatus.Started,
CreatedAt = DateTime.UtcNow, CreatedAt = DateTime.UtcNow,
Players = JsonSerializer.Serialize(action.DayModel.Players.Select(_ => _.Id)), Players = JsonSerializer.Serialize(action.DayModel.Players.Select(_ => _.Id)),
PostDate = action.DayModel.PostDate.Value PostDate = action.DayModel.PostDate.Value
}); });
dispatcher.Dispatch(new DayStateLoadedAction(day)); dispatcher.Dispatch(new DayLoadedAction(day));
} }
catch (Exception e) catch (Exception e)
{ {
@ -52,10 +100,10 @@ namespace KoogleApp.Store.DayFeature
} }
//var response = await _httpClient.PostAsJsonAsync("Feedback", action.UserFeedbackModel); //var response = await _httpClient.PostAsJsonAsync("Feedback", action.UserFeedbackModel);
if (1==1) if (day != null && string.IsNullOrEmpty(msg))
{ {
dispatcher.Dispatch(new AddDayStateAction(action.DayModel)); //dispatcher.Dispatch(new AddDayStateAction(action.DayModel));
dispatcher.Dispatch(new DayModelSubmitSuccessAction()); dispatcher.Dispatch(new DayModelSubmitSuccessAction(day));
} }
else else
{ {

View File

@ -1,7 +1,9 @@
using System.Text.Json; using Fluxor;
using Fluxor;
using KoogleApp.Model; using KoogleApp.Model;
using KoogleApp.Store.Game.Setup; using KoogleApp.Store.Game.Setup;
using KoogleApp.Store.Player;
using System.Text.Json;
using Microsoft.Identity.Client;
namespace KoogleApp.Store.DayFeature namespace KoogleApp.Store.DayFeature
{ {
@ -9,37 +11,54 @@ namespace KoogleApp.Store.DayFeature
{ {
[ReducerMethod] [ReducerMethod]
public static DayState OnCloseDayStateAction(DayState state, CloseDayStateAction action) public static DayState OnChangeDayStatusAction(DayState state, ChangeDayStatusAction action)
{ {
return state with return state with
{ {
Status = DayStatus.Finished Status = action.Status
}; };
} }
[ReducerMethod] [ReducerMethod]
public static DayState OnAddDayStateAction(DayState state, AddDayStateAction action) public static DaysState OnChangeDayStatusAction(DaysState state, ChangeDayStatusAction action)
{ {
return new DayState(0, action.DayModel.PostDate.Value, DayStatus.Started, PlayerIds: []); var newList = new List<DayState>(state.Days); // Kopie erstellen
var idx = state.Days.FindIndex(p => p.Id == action.DayState.Id);
if (idx >= 0)
{
newList[idx] = newList[idx] with { Status = action.Status }; // Element ändern
return state with { Days = newList };
} }
[ReducerMethod]
public static DaysState OnAddDayStateAction(DaysState state, AddDayStateAction action)
{
state.Days.Add(new DayState(0, action.DayModel.PostDate.Value, DayStatus.Started, PlayerIds: []));
return state; return state;
} }
[ReducerMethod]
public static DayState OnDayLoadedAction(DayState state, DayLoadedAction action)
{
var day = DayStateSelector.DbConvert(action.Day);
return day;
}
[ReducerMethod]
public static DayState OnChangeSelectedDay(DayState state, ChangeSelectedDay action)
{
return action.DayState with
{
Status = DayStatus.Started
};
}
[ReducerMethod] [ReducerMethod]
public static DayState OnDayStateLoadedAction(DayState state, DayStateLoadedAction action) public static DayState OnDayStateLoadedAction(DayState state, DayStateLoadedAction action)
{ {
return state with return state with
{ {
Id = action.Day.Id, Id = action.DayState.Id,
Date = action.Day.PostDate, Date = action.DayState.Date,
Status = action.Day.Status, Status = action.DayState.Status,
PlayerIds = JsonSerializer.Deserialize<int[]>(action.Day.Players) PlayerIds = action.DayState.PlayerIds
}; };
} }
@ -50,13 +69,41 @@ namespace KoogleApp.Store.DayFeature
{ {
Loaded = true, Loaded = true,
Year = action.Year, Year = action.Year,
Days = action.Days.Select(_ => new DayState(_.Id, _.PostDate, _.Status, PlayerIds: [])).ToList() Days = action.Days.Select(DayStateSelector.DbConvert).ToList()
}; };
}
[ReducerMethod]
public static DayState OnChangePlayerAvailableAction(DayState state,
ChangePlayerAvailableAction action)
{
if (state.Status != DayStatus.Started)
{
throw new InvalidOperationException("ChangePlayerAvailableAction not allowed when day not started");
}
var ids = state.PlayerIds.ToList();
if (action.IsAvailable)
{
ids.Add(action.PlayerId);
}
else
{
ids.Remove(action.PlayerId);
}
return state with
{
PlayerIds = ids.ToArray()
};
} }
// MODEL REDUCERS
[ReducerMethod(typeof(DayModelSubmitAction))] [ReducerMethod(typeof(DayModelSubmitAction))]
public static DayModelState OnSubmit(DayModelState state) public static DayModelState OnSubmit(DayModelState state)
{ {
@ -81,6 +128,15 @@ namespace KoogleApp.Store.DayFeature
}; };
} }
[ReducerMethod]
public static DaysState OnSubmitSuccess(DaysState state, DayModelSubmitSuccessAction action)
{
var newList = new List<DayState>(state.Days);
var dayState = DayStateSelector.DbConvert(action.Day);
newList.Add(dayState);
return state with { Days = newList };
}
[ReducerMethod] [ReducerMethod]
public static DayModelState OnSubmitFailure(DayModelState state, DayModelSubmitFailureAction action) public static DayModelState OnSubmitFailure(DayModelState state, DayModelSubmitFailureAction action)
{ {

View File

@ -0,0 +1,37 @@
using KoogleApp.Model;
using System;
using System.Text.Json;
namespace KoogleApp.Store.DayFeature
{
public static class DayStateSelector
{
public static DayState DbConvert(Day day)
{
return new DayState
{
Id = day.Id,
Date = day.PostDate,
Status = day.Status,
PlayerIds = JsonSerializer.Deserialize<int[]>(day.Players),
CreatedAt = day.CreatedAt,
ModifiedAt = day.ModifiedAt,
ModifiedBy = day.ModifiedBy
};
}
public static Day DbConvert(DayState dayState)
{
return new Day
{
Id = dayState.Id,
PostDate = dayState.Date,
Status = dayState.Status,
Players = JsonSerializer.Serialize(dayState.PlayerIds),
CreatedAt = dayState.CreatedAt,
ModifiedAt = dayState.ModifiedAt,
ModifiedBy = dayState.ModifiedBy
};
}
}
}

View File

@ -1,4 +1,5 @@
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices.JavaScript;
using Fluxor; using Fluxor;
using KoogleApp.Model; using KoogleApp.Model;
using KoogleApp.Store.ModelFeature; using KoogleApp.Store.ModelFeature;
@ -10,7 +11,8 @@ namespace KoogleApp.Store.DayFeature
{ {
New, New,
Started, Started,
Finished Postponed,
Closed
} }
[FeatureState] [FeatureState]
@ -23,9 +25,9 @@ namespace KoogleApp.Store.DayFeature
} }
[FeatureState] [FeatureState]
public record DayState(int Id, DateTime Date, DayStatus Status, int[] PlayerIds) public record DayState(int Id, DateTime Date, DayStatus Status, int[] PlayerIds, DateTime CreatedAt, DateTime? ModifiedAt, string ModifiedBy)
{ {
public DayState() : this(Id: 0, Date: DateTime.Today, Status: DayStatus.New, PlayerIds: []) public DayState() : this(Id: 0, Date: DateTime.Today, Status: DayStatus.New, PlayerIds: [], CreatedAt: DateTime.MinValue, ModifiedAt: DateTime.MinValue, ModifiedBy:String.Empty)
{ {
} }
} }

View File

@ -9,5 +9,5 @@ namespace KoogleApp.Store.Player
public record SelectPlayerAction(PlayerState? Player); public record SelectPlayerAction(PlayerState? Player);
public record ChangePlayerAvailableAction(int PlayerId, bool IsAvailable); public record ChangePlayerAvailableAction(int PlayerId, bool IsAvailable, DayState DayState, DaysState DaysState);
} }

View File

@ -14,7 +14,8 @@ namespace KoogleApp.Store.Player
var playerIds = action.DayState.PlayerIds; var playerIds = action.DayState.PlayerIds;
var players = action.Players var players = action.Players
.Select(p => new PlayerState(p.Name, p.Id, Available: playerIds.Contains(p.Id), PlayerStatus: PlayerStatus.Guest)) .Select(p => new PlayerState(p.Name, p.Id, Available: playerIds.Contains(p.Id),
PlayerStatus: PlayerStatus.Guest))
.ToList(); .ToList();
return state with { Players = players, Loaded = true }; return state with { Players = players, Loaded = true };
@ -44,7 +45,7 @@ namespace KoogleApp.Store.Player
} }
[ReducerMethod] [ReducerMethod]
public static PlayersState OnDayStateLoadedAction(PlayersState state, DayStateLoadedAction action) public static PlayersState OnDayLoadedAction(PlayersState state, DayLoadedAction action)
{ {
if (state.Players.Count == 0) if (state.Players.Count == 0)
{ {
@ -63,5 +64,21 @@ namespace KoogleApp.Store.Player
}; };
return res; return res;
} }
[ReducerMethod]
public static PlayersState OnChangeSelectedDay(PlayersState state, ChangeSelectedDay action)
{
var lst = new List<PlayerState>();
foreach (var playerState in state.Players)
{
lst.Add(playerState with
{
Available = action.DayState.PlayerIds.Contains(playerState.Id)
});
}
return state with { Players = lst };
}
} }
} }