Files
RpgRoller/RpgRoller/Components/Pages/HomeControls/CharacterPanel.razor.cs

335 lines
11 KiB
C#

using System.Diagnostics.CodeAnalysis;
using Microsoft.AspNetCore.Components;
using RpgRoller.Contracts;
namespace RpgRoller.Components.Pages.HomeControls;
[ExcludeFromCodeCoverage]
public partial class CharacterPanel
{
private void OpenCreateSkillModal(Guid? skillGroupId = null)
{
var selectedGroup = skillGroupId.HasValue
? SelectedCharacterSkillGroups.FirstOrDefault(group => group.Id == skillGroupId.Value)
: null;
CreateSkillInitialModel = new()
{
Name = string.Empty,
DiceRollDefinition = selectedGroup?.DiceRollDefinition ?? string.Empty,
SkillGroupId = selectedGroup?.Id.ToString() ?? string.Empty,
WildDice = selectedGroup?.WildDice ?? (IsD6 ? 1 : 0),
AllowFumble = selectedGroup?.AllowFumble ?? IsD6
};
CreateSkillFormVersion++;
ShowCreateSkillModal = true;
}
private void OpenEditSkillModal(SkillSummary skill)
{
EditingSkillId = skill.Id;
EditSkillInitialModel = new()
{
Name = skill.Name,
DiceRollDefinition = skill.DiceRollDefinition,
SkillGroupId = skill.SkillGroupId?.ToString() ?? string.Empty,
WildDice = skill.WildDice,
AllowFumble = skill.AllowFumble
};
EditSkillFormVersion++;
ShowEditSkillModal = true;
}
private void CloseSkillModals()
{
ShowCreateSkillModal = false;
ShowEditSkillModal = false;
EditingSkillId = null;
}
private async Task OnSkillCreatedAsync(Guid skillId)
{
CloseSkillModals();
await SkillCreated.InvokeAsync(skillId);
}
private async Task OnSkillUpdatedAsync(Guid skillId)
{
CloseSkillModals();
await SkillUpdated.InvokeAsync(skillId);
}
private async Task OnRollVisibilityChangedAsync(ChangeEventArgs args)
{
var selectedVisibility = args.Value?.ToString() ?? "public";
await RollVisibilityChanged.InvokeAsync(selectedVisibility);
}
private async Task RollSkillAsync(Guid skillId)
{
await RollRequested.InvokeAsync(skillId);
}
private void OpenCreateSkillGroupModal()
{
SkillGroupState.Model.Name = string.Empty;
SkillGroupState.Model.DiceRollDefinition = string.Empty;
SkillGroupState.Model.WildDice = IsD6 ? 1 : 0;
SkillGroupState.Model.AllowFumble = IsD6;
SkillGroupState.ResetValidation();
ShowCreateSkillGroupModal = true;
}
private void OpenEditSkillGroupModal(SkillGroupSummary skillGroup)
{
EditingSkillGroupId = skillGroup.Id;
SkillGroupState.Model.Name = skillGroup.Name;
SkillGroupState.Model.DiceRollDefinition = skillGroup.DiceRollDefinition;
SkillGroupState.Model.WildDice = skillGroup.WildDice;
SkillGroupState.Model.AllowFumble = skillGroup.AllowFumble;
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 (string.IsNullOrWhiteSpace(SkillGroupState.Model.DiceRollDefinition))
SkillGroupState.Errors["diceRollDefinition"] = "Expression is required.";
if (IsD6 && SkillGroupState.Model.WildDice < 1)
SkillGroupState.Errors["wildDice"] = "D6 groups require at least one wild die.";
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(),
SkillGroupState.Model.DiceRollDefinition.Trim(),
SkillGroupState.Model.WildDice,
SkillGroupState.Model.AllowFumble));
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 (string.IsNullOrWhiteSpace(SkillGroupState.Model.DiceRollDefinition))
SkillGroupState.Errors["diceRollDefinition"] = "Expression is required.";
if (IsD6 && SkillGroupState.Model.WildDice < 1)
SkillGroupState.Errors["wildDice"] = "D6 groups require at least one wild die.";
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(),
SkillGroupState.Model.DiceRollDefinition.Trim(),
SkillGroupState.Model.WildDice,
SkillGroupState.Model.AllowFumble));
CloseSkillGroupModals();
await SkillGroupUpdated.InvokeAsync(updatedGroup.Id);
}
catch (ApiRequestException ex)
{
SkillGroupState.ErrorMessage = ex.Message;
}
finally
{
IsSubmittingSkillGroup = false;
}
}
private async Task DeleteSkillAsync(Guid skillId)
{
try
{
await ApiClient.RequestAsync<bool>("DELETE", $"/api/skills/{skillId}");
await SkillDeleted.InvokeAsync(skillId);
}
catch (ApiRequestException ex)
{
await ErrorOccurred.InvokeAsync(ex.Message);
}
}
private async Task DeleteSkillGroupAsync(Guid skillGroupId)
{
try
{
await ApiClient.RequestAsync<bool>("DELETE", $"/api/skill-groups/{skillGroupId}");
await SkillGroupDeleted.InvokeAsync(skillGroupId);
}
catch (ApiRequestException ex)
{
await ErrorOccurred.InvokeAsync(ex.Message);
}
}
private bool SkillMatchesFilter(SkillSummary skill)
{
if (string.IsNullOrWhiteSpace(SkillFilterText))
return true;
var filter = SkillFilterText.Trim();
return skill.Name.Contains(filter, StringComparison.OrdinalIgnoreCase) ||
skill.DiceRollDefinition.Contains(filter, StringComparison.OrdinalIgnoreCase);
}
private static string InitialsFor(string value)
{
var words = value.Split(' ', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
if (words.Length == 0)
return "?";
if (words.Length == 1)
return words[0].Length >= 2 ? words[0][..2].ToUpperInvariant() : words[0].ToUpperInvariant();
return string.Concat(words[0][0], words[1][0]).ToUpperInvariant();
}
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; }
private string SkillFilterText { get; set; } = string.Empty;
[Inject]
private RpgRollerApiClient ApiClient { get; set; } = null!;
[Parameter]
public bool IsCampaignDataLoading { get; set; }
[Parameter]
public CampaignDetails? SelectedCampaign { get; set; }
[Parameter]
public Guid? SelectedCharacterId { get; set; }
[Parameter]
public CharacterSummary? SelectedCharacter { get; set; }
[Parameter]
public bool IsMutating { get; set; }
[Parameter]
public IReadOnlyList<SkillSummary> SelectedCharacterSkills { get; set; } = [];
[Parameter]
public IReadOnlyList<SkillGroupSummary> SelectedCharacterSkillGroups { get; set; } = [];
[Parameter]
public bool IsD6 { get; set; }
[Parameter]
public string RollVisibility { get; set; } = "public";
[Parameter]
public EventCallback<string> RollVisibilityChanged { get; set; }
[Parameter]
public Func<Guid, string> OwnerLabel { get; set; } = _ => string.Empty;
[Parameter]
public Func<SkillSummary, string> SkillDefinitionLabel { get; set; } = _ => string.Empty;
[Parameter]
public Func<CharacterSummary, bool> CanEditCharacter { get; set; } = _ => false;
[Parameter]
public Func<SkillSummary, bool> CanEditSkill { get; set; } = _ => false;
[Parameter]
public EventCallback<Guid> CharacterSelected { get; set; }
[Parameter]
public EventCallback<CharacterSummary> EditCharacterRequested { get; set; }
[Parameter]
public EventCallback<Guid> SkillCreated { get; set; }
[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> SkillDeleted { get; set; }
[Parameter]
public EventCallback<Guid> SkillGroupDeleted { get; set; }
[Parameter]
public EventCallback<string> ErrorOccurred { get; set; }
[Parameter]
public EventCallback<Guid> RollRequested { get; set; }
}