@inherits LayoutComponentBase @implements IDisposable @inject IUserSessionService Session @inject IUserContextAccessor UserContext @inject ISessionCredentialStore CredStore @inject ISessionManager SessionManager @inject NavigationManager Nav @inject IJSRuntime JS @inject SharepointToolbox.Web.Services.OAuth.IOAuthFlowCache OAuthCache @using Microsoft.AspNetCore.Components.Authorization @using Microsoft.AspNetCore.WebUtilities @using Microsoft.JSInterop @using SharepointToolbox.Web.Core.Models @using SharepointToolbox.Web.Services.Session
@if (UserContext.IsAuthenticated) { @Body } else {
Loading…
}
@code { private bool _sidebarCollapsed; private bool _hasCredentials; private string _credUsername = string.Empty; private SessionCredentialsModal? _credModal; protected override void OnInitialized() { Session.ProfileChanged += OnProfileChanged; UserContext.Initialized += OnUserContextInitialized; } private void OnUserContextInitialized() => InvokeAsync(StateHasChanged); protected override async Task OnAfterRenderAsync(bool firstRender) { if (!firstRender) return; // Apply persisted theme preference await ApplyThemeAsync(); // Pick up token_key from OAuth callback redirect before checking credential state await HandleOAuthCallbackAsync(); await RefreshCredentialState(); // Check for connect_error query param var uri = new Uri(Nav.Uri); var query = QueryHelpers.ParseQuery(uri.Query); if (query.TryGetValue("connect_error", out var err) && !string.IsNullOrEmpty(err)) { Nav.NavigateTo(uri.GetLeftPart(UriPartial.Path), replace: true); if (_credModal is not null) { // Surface the failure reason instead of silently reopening the modal await _credModal.ShowAsync(err!); } } // If profile selected but no credentials β†’ show modal if (Session.HasProfile && !_hasCredentials && _credModal is not null) await _credModal.ShowAsync(); } private async Task HandleOAuthCallbackAsync() { var uri = new Uri(Nav.Uri); var query = QueryHelpers.ParseQuery(uri.Query); if (!query.TryGetValue("token_key", out var tokenKey) || string.IsNullOrEmpty(tokenKey)) return; var tokens = OAuthCache.GetAndRemoveTokens(tokenKey!); if (tokens is not null) { await CredStore.SetAsync(tokens); await SessionManager.ClearAllAsync(); } // Strip token_key from URL bar Nav.NavigateTo(uri.GetLeftPart(UriPartial.Path), replace: true); } private async Task RefreshCredentialState() { var tokens = await CredStore.GetAsync(); _hasCredentials = tokens is not null && !string.IsNullOrEmpty(tokens.RefreshToken); _credUsername = tokens?.UserPrincipalName ?? string.Empty; await InvokeAsync(StateHasChanged); } private async Task ReconnectAsync() { await CredStore.ClearAsync(); await SessionManager.ClearAllAsync(); _hasCredentials = false; _credUsername = string.Empty; if (Session.HasProfile && _credModal is not null) await _credModal.ShowAsync(); } private async Task OnCredentialsConnected() { await RefreshCredentialState(); } private void OnProfileChanged() { InvokeAsync(async () => { StateHasChanged(); // New profile selected β†’ prompt for credentials if none if (Session.HasProfile && !_hasCredentials && _credModal is not null) await _credModal.ShowAsync(); }); } private async Task ApplyThemeAsync() { try { await JS.InvokeVoidAsync("sptb.setTheme", Session.Settings.Theme); } catch (JSException) { /* best-effort; JS not yet available */ } } private void ToggleSidebar() => _sidebarCollapsed = !_sidebarCollapsed; private static string RoleChipClass(UserRole role) => role switch { UserRole.Admin => "chip-red", UserRole.TechN1 => "chip-green", _ => "chip-blue" }; public void Dispose() { Session.ProfileChanged -= OnProfileChanged; UserContext.Initialized -= OnUserContextInitialized; } }