diff --git a/README.md b/README.md index c782a76..00f462f 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,7 @@ Gameplay capabilities now include: - Character edit flow supports unlinking from campaigns (owner/GM/admin) and assigning to any existing campaign via expanded campaign options - Campaign management supports character deletion by character owner or admin - Shared top header control across workspace and admin views (consistent navigation/logout behavior) +- Admin menu navigation now directly targets `Play` or `Campaign Management` workspace screens ## Prerequisites diff --git a/RpgRoller/Components/Pages/Home.razor b/RpgRoller/Components/Pages/Home.razor index 8366693..c653c61 100644 --- a/RpgRoller/Components/Pages/Home.razor +++ b/RpgRoller/Components/Pages/Home.razor @@ -22,10 +22,10 @@ break; case HomeViewMode.Workspace: - + break; case HomeViewMode.Admin: - + break; } diff --git a/RpgRoller/Components/Pages/Home.razor.cs b/RpgRoller/Components/Pages/Home.razor.cs index e7cf0f5..52aeace 100644 --- a/RpgRoller/Components/Pages/Home.razor.cs +++ b/RpgRoller/Components/Pages/Home.razor.cs @@ -22,50 +22,60 @@ public partial class Home try { _ = await ApiClient.RequestAsync("GET", "/api/me"); + WorkspaceScreenOverride = null; CurrentView = HomeViewMode.Workspace; ClearStatus(); } catch (ApiRequestException ex) when (ex.StatusCode == 401) { + WorkspaceScreenOverride = null; CurrentView = HomeViewMode.Anonymous; ClearStatus(); } catch (ApiRequestException ex) { + WorkspaceScreenOverride = null; CurrentView = HomeViewMode.Anonymous; SetStatus(ex.Message, true); } } - private void OnLoggedInAsync() + private Task OnLoggedInAsync() { + WorkspaceScreenOverride = null; CurrentView = HomeViewMode.Workspace; ClearStatus(); + return InvokeAsync(StateHasChanged); } - private void OnAdminRequested() + private Task OnAdminRequestedAsync() { CurrentView = HomeViewMode.Admin; ClearStatus(); + return InvokeAsync(StateHasChanged); } - private void OnWorkspaceRequested() + private Task OnWorkspaceRequestedAsync(string screen) { + WorkspaceScreenOverride = NormalizeWorkspaceScreen(screen) ?? "play"; CurrentView = HomeViewMode.Workspace; ClearStatus(); + return InvokeAsync(StateHasChanged); } - private void OnLoggedOutAsync(string? message) + private Task OnLoggedOutAsync(string? message) { + WorkspaceScreenOverride = null; CurrentView = HomeViewMode.Anonymous; if (string.IsNullOrWhiteSpace(message)) { ClearStatus(); - return; + return InvokeAsync(StateHasChanged); } var isError = message.Contains("expired", StringComparison.OrdinalIgnoreCase); SetStatus(message, isError); + return InvokeAsync(StateHasChanged); } private void SetStatus(string message, bool isError) @@ -80,7 +90,19 @@ public partial class Home StatusIsError = false; } + private static string? NormalizeWorkspaceScreen(string? screen) + { + if (string.Equals(screen, "management", StringComparison.OrdinalIgnoreCase)) + return "management"; + + if (string.Equals(screen, "play", StringComparison.OrdinalIgnoreCase)) + return "play"; + + return null; + } + private HomeViewMode CurrentView { get; set; } = HomeViewMode.Loading; + private string? WorkspaceScreenOverride { get; set; } private string? StatusMessage { get; set; } private bool StatusIsError { get; set; } private bool HasInitialized { get; set; } diff --git a/RpgRoller/Components/Pages/HomeControls/AdminHome.razor.cs b/RpgRoller/Components/Pages/HomeControls/AdminHome.razor.cs index d015df4..94f61fc 100644 --- a/RpgRoller/Components/Pages/HomeControls/AdminHome.razor.cs +++ b/RpgRoller/Components/Pages/HomeControls/AdminHome.razor.cs @@ -46,18 +46,14 @@ public partial class AdminHome } } - private async Task OpenPlayAsync() + private Task OpenPlayAsync() { - IsScreenMenuOpen = false; - await JS.InvokeVoidAsync("rpgRollerApi.setSessionValue", ScreenSessionKey, "play"); - await WorkspaceRequested.InvokeAsync(); + return OpenWorkspaceAsync("play"); } - private async Task OpenCampaignManagementAsync() + private Task OpenCampaignManagementAsync() { - IsScreenMenuOpen = false; - await JS.InvokeVoidAsync("rpgRollerApi.setSessionValue", ScreenSessionKey, "management"); - await WorkspaceRequested.InvokeAsync(); + return OpenWorkspaceAsync("management"); } private Task OpenAdminAsync() @@ -168,6 +164,12 @@ public partial class AdminHome IsScreenMenuOpen = !IsScreenMenuOpen; } + private async Task OpenWorkspaceAsync(string screen) + { + IsScreenMenuOpen = false; + await WorkspaceRequested.InvokeAsync(screen); + } + [Inject] private RpgRollerApiClient ApiClient { get; set; } = null!; @@ -195,11 +197,9 @@ public partial class AdminHome } } - private const string ScreenSessionKey = "screen"; - [Parameter] public EventCallback LoggedOut { get; set; } [Parameter] - public EventCallback WorkspaceRequested { get; set; } + public EventCallback WorkspaceRequested { get; set; } } diff --git a/RpgRoller/Components/Pages/Workspace.razor.cs b/RpgRoller/Components/Pages/Workspace.razor.cs index f05fec4..1478879 100644 --- a/RpgRoller/Components/Pages/Workspace.razor.cs +++ b/RpgRoller/Components/Pages/Workspace.razor.cs @@ -22,9 +22,18 @@ public partial class Workspace : IAsyncDisposable private async Task InitializeAsync() { - var storedScreen = await JS.InvokeAsync("rpgRollerApi.getSessionValue", ScreenSessionKey); - if (string.Equals(storedScreen, "management", StringComparison.OrdinalIgnoreCase)) - CurrentScreen = "management"; + var requestedScreen = NormalizeRequestedScreen(RequestedScreen); + if (requestedScreen is not null) + { + CurrentScreen = requestedScreen; + await JS.InvokeVoidAsync("rpgRollerApi.setSessionValue", ScreenSessionKey, CurrentScreen); + } + else + { + var storedScreen = await JS.InvokeAsync("rpgRollerApi.getSessionValue", ScreenSessionKey); + if (string.Equals(storedScreen, "management", StringComparison.OrdinalIgnoreCase)) + CurrentScreen = "management"; + } var storedPanel = await JS.InvokeAsync("rpgRollerApi.getSessionValue", MobilePanelSessionKey); if (string.Equals(storedPanel, "log", StringComparison.OrdinalIgnoreCase)) @@ -225,7 +234,7 @@ public partial class Workspace : IAsyncDisposable private async Task SwitchScreenAsync(string screen) { - CurrentScreen = string.Equals(screen, "management", StringComparison.OrdinalIgnoreCase) ? "management" : "play"; + CurrentScreen = NormalizeRequestedScreen(screen) ?? "play"; IsScreenMenuOpen = false; await JS.InvokeVoidAsync("rpgRollerApi.setSessionValue", ScreenSessionKey, CurrentScreen); } @@ -522,6 +531,17 @@ public partial class Workspace : IAsyncDisposable return string.Equals(visibility, "private", StringComparison.OrdinalIgnoreCase) ? "private" : "public"; } + private static string? NormalizeRequestedScreen(string? screen) + { + if (string.Equals(screen, "management", StringComparison.OrdinalIgnoreCase)) + return "management"; + + if (string.Equals(screen, "play", StringComparison.OrdinalIgnoreCase)) + return "play"; + + return null; + } + private bool CanEditSkill(SkillSummary skill) { if (SelectedCampaign is null) @@ -822,6 +842,9 @@ public partial class Workspace : IAsyncDisposable [Parameter] public EventCallback AdminRequested { get; set; } + [Parameter] + public string? RequestedScreen { get; set; } + private string? SelectedCampaignName => SelectedCampaign?.Name; private CharacterSummary? SelectedCharacter =>