add fluxor club states

This commit is contained in:
beo3000 2025-12-23 18:26:01 +01:00
parent 0bc0de2215
commit 33fc3323e2
4 changed files with 395 additions and 0 deletions

View File

@ -0,0 +1,73 @@
using Koogle.Application.DTOs;
namespace Koogle.Web.Store.ClubState;
/// <summary>
/// Action to load all clubs.
/// </summary>
public record LoadClubsAction;
/// <summary>
/// Action dispatched when clubs are loaded successfully.
/// </summary>
public record LoadClubsSuccessAction(IReadOnlyList<ClubDto> Clubs);
/// <summary>
/// Action dispatched when loading clubs fails.
/// </summary>
public record LoadClubsFailureAction(string Error);
/// <summary>
/// Action to create a new club.
/// </summary>
public record CreateClubAction(CreateClubDto Dto);
/// <summary>
/// Action dispatched when club is created successfully.
/// </summary>
public record CreateClubSuccessAction(ClubDto Club);
/// <summary>
/// Action dispatched when creating club fails.
/// </summary>
public record CreateClubFailureAction(string Error);
/// <summary>
/// Action to update an existing club.
/// </summary>
public record UpdateClubAction(UpdateClubDto Dto);
/// <summary>
/// Action dispatched when club is updated successfully.
/// </summary>
public record UpdateClubSuccessAction(ClubDto Club);
/// <summary>
/// Action dispatched when updating club fails.
/// </summary>
public record UpdateClubFailureAction(string Error);
/// <summary>
/// Action to delete a club.
/// </summary>
public record DeleteClubAction(Guid Id);
/// <summary>
/// Action dispatched when club is deleted successfully.
/// </summary>
public record DeleteClubSuccessAction(Guid Id);
/// <summary>
/// Action dispatched when deleting club fails.
/// </summary>
public record DeleteClubFailureAction(string Error);
/// <summary>
/// Action to select a club for editing.
/// </summary>
public record SelectClubAction(ClubDto? Club);
/// <summary>
/// Action to clear club error state.
/// </summary>
public record ClearClubErrorAction;

View File

@ -0,0 +1,112 @@
using Fluxor;
using Koogle.Application.Interfaces;
namespace Koogle.Web.Store.ClubState;
/// <summary>
/// Side effects for club state management.
/// Handles async operations like API calls.
/// </summary>
public class ClubEffects
{
private readonly IClubService _clubService;
private readonly ILogger<ClubEffects> _logger;
/// <summary>
/// Initializes a new instance of the ClubEffects class.
/// </summary>
public ClubEffects(IClubService clubService, ILogger<ClubEffects> logger)
{
_clubService = clubService;
_logger = logger;
}
/// <summary>
/// Handles LoadClubsAction - loads all clubs from service.
/// </summary>
[EffectMethod]
public async Task HandleLoadClubs(LoadClubsAction action, IDispatcher dispatcher)
{
try
{
_logger.LogDebug("Loading clubs");
var clubs = await _clubService.GetAllAsync();
dispatcher.Dispatch(new LoadClubsSuccessAction(clubs));
_logger.LogInformation("Loaded {Count} clubs", clubs.Count);
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to load clubs");
dispatcher.Dispatch(new LoadClubsFailureAction(ex.Message));
}
}
/// <summary>
/// Handles CreateClubAction - creates a new club.
/// </summary>
[EffectMethod]
public async Task HandleCreateClub(CreateClubAction action, IDispatcher dispatcher)
{
try
{
_logger.LogDebug("Creating club {Name}", action.Dto.Name);
var club = await _clubService.CreateAsync(action.Dto);
dispatcher.Dispatch(new CreateClubSuccessAction(club));
_logger.LogInformation("Created club {Name} with ID {Id}", club.Name, club.Id);
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to create club {Name}", action.Dto.Name);
dispatcher.Dispatch(new CreateClubFailureAction(ex.Message));
}
}
/// <summary>
/// Handles UpdateClubAction - updates an existing club.
/// </summary>
[EffectMethod]
public async Task HandleUpdateClub(UpdateClubAction action, IDispatcher dispatcher)
{
try
{
_logger.LogDebug("Updating club {Id}", action.Dto.Id);
var club = await _clubService.UpdateAsync(action.Dto);
dispatcher.Dispatch(new UpdateClubSuccessAction(club));
_logger.LogInformation("Updated club {Name}", club.Name);
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to update club {Id}", action.Dto.Id);
dispatcher.Dispatch(new UpdateClubFailureAction(ex.Message));
}
}
/// <summary>
/// Handles DeleteClubAction - deletes a club.
/// </summary>
[EffectMethod]
public async Task HandleDeleteClub(DeleteClubAction action, IDispatcher dispatcher)
{
try
{
_logger.LogDebug("Deleting club {Id}", action.Id);
var success = await _clubService.DeleteAsync(action.Id);
if (success)
{
dispatcher.Dispatch(new DeleteClubSuccessAction(action.Id));
_logger.LogInformation("Deleted club {Id}", action.Id);
}
else
{
dispatcher.Dispatch(new DeleteClubFailureAction("Club konnte nicht gelöscht werden."));
_logger.LogWarning("Failed to delete club {Id} - not found or already deleted", action.Id);
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to delete club {Id}", action.Id);
dispatcher.Dispatch(new DeleteClubFailureAction(ex.Message));
}
}
}

View File

@ -0,0 +1,163 @@
using Fluxor;
namespace Koogle.Web.Store.ClubState;
/// <summary>
/// Reducers for club state management.
/// </summary>
public static class ClubReducers
{
/// <summary>
/// Handles LoadClubsAction - sets loading state.
/// </summary>
[ReducerMethod(typeof(LoadClubsAction))]
public static ClubState OnLoadClubs(ClubState state)
=> state with
{
IsLoading = true,
Error = null
};
/// <summary>
/// Handles LoadClubsSuccessAction - updates clubs list.
/// </summary>
[ReducerMethod]
public static ClubState OnLoadClubsSuccess(ClubState state, LoadClubsSuccessAction action)
=> state with
{
Clubs = action.Clubs,
IsLoading = false
};
/// <summary>
/// Handles LoadClubsFailureAction - sets error state.
/// </summary>
[ReducerMethod]
public static ClubState OnLoadClubsFailure(ClubState state, LoadClubsFailureAction action)
=> state with
{
IsLoading = false,
Error = action.Error
};
/// <summary>
/// Handles CreateClubAction - sets loading state.
/// </summary>
[ReducerMethod(typeof(CreateClubAction))]
public static ClubState OnCreateClub(ClubState state)
=> state with
{
IsLoading = true,
Error = null
};
/// <summary>
/// Handles CreateClubSuccessAction - adds club to list.
/// </summary>
[ReducerMethod]
public static ClubState OnCreateClubSuccess(ClubState state, CreateClubSuccessAction action)
=> state with
{
Clubs = [.. state.Clubs, action.Club],
IsLoading = false
};
/// <summary>
/// Handles CreateClubFailureAction - sets error state.
/// </summary>
[ReducerMethod]
public static ClubState OnCreateClubFailure(ClubState state, CreateClubFailureAction action)
=> state with
{
IsLoading = false,
Error = action.Error
};
/// <summary>
/// Handles UpdateClubAction - sets loading state.
/// </summary>
[ReducerMethod(typeof(UpdateClubAction))]
public static ClubState OnUpdateClub(ClubState state)
=> state with
{
IsLoading = true,
Error = null
};
/// <summary>
/// Handles UpdateClubSuccessAction - replaces club in list.
/// </summary>
[ReducerMethod]
public static ClubState OnUpdateClubSuccess(ClubState state, UpdateClubSuccessAction action)
=> state with
{
Clubs = state.Clubs.Select(c => c.Id == action.Club.Id ? action.Club : c).ToList(),
SelectedClub = state.SelectedClub?.Id == action.Club.Id ? action.Club : state.SelectedClub,
IsLoading = false
};
/// <summary>
/// Handles UpdateClubFailureAction - sets error state.
/// </summary>
[ReducerMethod]
public static ClubState OnUpdateClubFailure(ClubState state, UpdateClubFailureAction action)
=> state with
{
IsLoading = false,
Error = action.Error
};
/// <summary>
/// Handles DeleteClubAction - sets loading state.
/// </summary>
[ReducerMethod(typeof(DeleteClubAction))]
public static ClubState OnDeleteClub(ClubState state)
=> state with
{
IsLoading = true,
Error = null
};
/// <summary>
/// Handles DeleteClubSuccessAction - removes club from list.
/// </summary>
[ReducerMethod]
public static ClubState OnDeleteClubSuccess(ClubState state, DeleteClubSuccessAction action)
=> state with
{
Clubs = state.Clubs.Where(c => c.Id != action.Id).ToList(),
SelectedClub = state.SelectedClub?.Id == action.Id ? null : state.SelectedClub,
IsLoading = false
};
/// <summary>
/// Handles DeleteClubFailureAction - sets error state.
/// </summary>
[ReducerMethod]
public static ClubState OnDeleteClubFailure(ClubState state, DeleteClubFailureAction action)
=> state with
{
IsLoading = false,
Error = action.Error
};
/// <summary>
/// Handles SelectClubAction - sets selected club.
/// </summary>
[ReducerMethod]
public static ClubState OnSelectClub(ClubState state, SelectClubAction action)
=> state with
{
SelectedClub = action.Club
};
/// <summary>
/// Handles ClearClubErrorAction - clears error state.
/// </summary>
[ReducerMethod(typeof(ClearClubErrorAction))]
public static ClubState OnClearError(ClubState state)
=> state with
{
Error = null
};
}

View File

@ -0,0 +1,47 @@
using Fluxor;
using Koogle.Application.DTOs;
namespace Koogle.Web.Store.ClubState;
/// <summary>
/// Fluxor state for club management.
/// </summary>
[FeatureState]
public record ClubState
{
/// <summary>
/// List of all clubs.
/// </summary>
public IReadOnlyList<ClubDto> Clubs { get; init; } = [];
/// <summary>
/// Currently selected club for editing.
/// </summary>
public ClubDto? SelectedClub { get; init; }
/// <summary>
/// Indicates whether a club operation is in progress.
/// </summary>
public bool IsLoading { get; init; }
/// <summary>
/// Error message if operation failed.
/// </summary>
public string? Error { get; init; }
/// <summary>
/// Private constructor for Fluxor initialization.
/// </summary>
private ClubState() { }
/// <summary>
/// Creates the initial state.
/// </summary>
public static ClubState Initial => new()
{
Clubs = [],
SelectedClub = null,
IsLoading = false,
Error = null
};
}