Add skill groups and GM character owner transfer across stack

This commit is contained in:
2026-02-26 13:54:17 +01:00
parent bf3a6fa645
commit 04bc8095e6
31 changed files with 995 additions and 1180 deletions

View File

@@ -13,6 +13,7 @@ public partial class CharacterPanel
{
Name = string.Empty,
DiceRollDefinition = string.Empty,
SkillGroupId = string.Empty,
WildDice = IsD6 ? 1 : 0,
AllowFumble = IsD6
};
@@ -28,6 +29,7 @@ public partial class CharacterPanel
{
Name = skill.Name,
DiceRollDefinition = skill.DiceRollDefinition,
SkillGroupId = skill.SkillGroupId?.ToString() ?? string.Empty,
WildDice = skill.WildDice,
AllowFumble = skill.AllowFumble
};
@@ -66,6 +68,97 @@ public partial class CharacterPanel
await RollRequested.InvokeAsync(skillId);
}
private void OpenCreateSkillGroupModal()
{
SkillGroupState.Model.Name = string.Empty;
SkillGroupState.ResetValidation();
ShowCreateSkillGroupModal = true;
}
private void OpenEditSkillGroupModal(SkillGroupSummary skillGroup)
{
EditingSkillGroupId = skillGroup.Id;
SkillGroupState.Model.Name = skillGroup.Name;
SkillGroupState.ResetValidation();
ShowEditSkillGroupModal = true;
}
private void CloseSkillGroupModals()
{
ShowCreateSkillGroupModal = false;
ShowEditSkillGroupModal = false;
EditingSkillGroupId = null;
SkillGroupState.ResetValidation();
}
private async Task SubmitCreateSkillGroupAsync()
{
SkillGroupState.ResetValidation();
if (string.IsNullOrWhiteSpace(SkillGroupState.Model.Name))
SkillGroupState.Errors["name"] = "Skill group name is required.";
if (!SelectedCharacterId.HasValue)
SkillGroupState.Errors["character"] = "Select a character first.";
if (SkillGroupState.Errors.Count > 0)
{
SkillGroupState.ErrorMessage = "Resolve validation issues before submitting.";
return;
}
IsSubmittingSkillGroup = true;
try
{
var selectedCharacterId = SelectedCharacterId!.Value;
var createdGroup = await ApiClient.RequestAsync<SkillGroupSummary>("POST", $"/api/characters/{selectedCharacterId}/skill-groups", new CreateSkillGroupRequest(SkillGroupState.Model.Name.Trim()));
CloseSkillGroupModals();
await SkillGroupCreated.InvokeAsync(createdGroup.Id);
}
catch (ApiRequestException ex)
{
SkillGroupState.ErrorMessage = ex.Message;
}
finally
{
IsSubmittingSkillGroup = false;
}
}
private async Task SubmitUpdateSkillGroupAsync()
{
SkillGroupState.ResetValidation();
if (string.IsNullOrWhiteSpace(SkillGroupState.Model.Name))
SkillGroupState.Errors["name"] = "Skill group name is required.";
if (!EditingSkillGroupId.HasValue)
SkillGroupState.Errors["group"] = "Select a skill group first.";
if (SkillGroupState.Errors.Count > 0)
{
SkillGroupState.ErrorMessage = "Resolve validation issues before submitting.";
return;
}
IsSubmittingSkillGroup = true;
try
{
var editingSkillGroupId = EditingSkillGroupId!.Value;
var updatedGroup = await ApiClient.RequestAsync<SkillGroupSummary>("PUT", $"/api/skill-groups/{editingSkillGroupId}", new UpdateSkillGroupRequest(SkillGroupState.Model.Name.Trim()));
CloseSkillGroupModals();
await SkillGroupUpdated.InvokeAsync(updatedGroup.Id);
}
catch (ApiRequestException ex)
{
SkillGroupState.ErrorMessage = ex.Message;
}
finally
{
IsSubmittingSkillGroup = false;
}
}
private static string InitialsFor(string value)
{
var words = value.Split(' ', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
@@ -80,11 +173,19 @@ public partial class CharacterPanel
private bool ShowCreateSkillModal { get; set; }
private bool ShowEditSkillModal { get; set; }
private bool ShowCreateSkillGroupModal { get; set; }
private bool ShowEditSkillGroupModal { get; set; }
private Guid? EditingSkillId { get; set; }
private Guid? EditingSkillGroupId { get; set; }
private SkillFormModel CreateSkillInitialModel { get; set; } = new();
private SkillFormModel EditSkillInitialModel { get; set; } = new();
private FormState<SkillGroupFormModel> SkillGroupState { get; } = new();
private int CreateSkillFormVersion { get; set; }
private int EditSkillFormVersion { get; set; }
private bool IsSubmittingSkillGroup { get; set; }
[Inject]
private RpgRollerApiClient ApiClient { get; set; } = null!;
[Parameter]
public bool IsCampaignDataLoading { get; set; }
@@ -104,6 +205,9 @@ public partial class CharacterPanel
[Parameter]
public IReadOnlyList<SkillSummary> SelectedCharacterSkills { get; set; } = [];
[Parameter]
public IReadOnlyList<SkillGroupSummary> SelectedCharacterSkillGroups { get; set; } = [];
[Parameter]
public bool IsD6 { get; set; }
@@ -140,6 +244,12 @@ public partial class CharacterPanel
[Parameter]
public EventCallback<Guid> SkillUpdated { get; set; }
[Parameter]
public EventCallback<Guid> SkillGroupCreated { get; set; }
[Parameter]
public EventCallback<Guid> SkillGroupUpdated { get; set; }
[Parameter]
public EventCallback<Guid> RollRequested { get; set; }
}