diff --git a/LayerComponents/CascadingState.razor b/LayerComponents/CascadingState.razor
index 9f6bfbe..9cae022 100644
--- a/LayerComponents/CascadingState.razor
+++ b/LayerComponents/CascadingState.razor
@@ -27,6 +27,8 @@
public PublicCacheData PublicCacheData { get; private set; } = new();
/// Whether a root is signed in (its JWT is still valid).
public bool IsSignedIn { get; private set; }
+ /// The session has been read once: from then on a null PersonaId means the login has no persona, not "not yet".
+ public bool IsSessionLoaded { get; private set; }
/// The root's login name, shown to its owner only.
public string RootUserName { get; private set; }
/// The root's personas.
@@ -93,6 +95,7 @@
if (!IsSignedIn)
{
ClearSession();
+ IsSessionLoaded = true;
StateHasChanged();
return;
}
@@ -105,10 +108,12 @@
{
PersonaId = null;
Persona = null;
+ IsSessionLoaded = true;
StateHasChanged();
return;
}
+ IsSessionLoaded = true;
await SwitchPersona(personaId, cancellationToken);
}
diff --git a/Pages/Index.razor b/Pages/Index.razor
index 173c7bc..234b8a3 100644
--- a/Pages/Index.razor
+++ b/Pages/Index.razor
@@ -155,6 +155,7 @@
(double Latitude, double Longitude)? position;
string positionError;
string loadedPersonaId;
+ bool waitingForPersona;
FeedQuery lastQuery;
DateTime? lastPollAt;
TimeSpan? lastLoadTook;
@@ -183,9 +184,11 @@
return;
}
+ // (while the session is still being read the persona isn't known yet: the feed is loading, not empty)
if (CascadingState.PersonaId is null)
{
- IsLoading = false;
+ waitingForPersona = !CascadingState.IsSessionLoaded;
+ IsLoading = waitingForPersona;
return;
}
@@ -219,11 +222,19 @@
return true;
}
- // The persona changed (NavMenu's switcher): everything on the page belongs to the old one.
+ // The persona is known (the session was read after the page opened) or changed (NavMenu's switcher): everything on the
+ // page belongs to it.
protected override async Task OnParametersSetAsync()
{
- if (CascadingState.PersonaId is null || CascadingState.PersonaId == loadedPersonaId || IsLoading && loadedPersonaId is null)
+ if (waitingForPersona && CascadingState.IsSessionLoaded && CascadingState.PersonaId is null)
+ {
+ waitingForPersona = false;
+ IsLoading = false;
return;
+ }
+ if (CascadingState.PersonaId is null || CascadingState.PersonaId == loadedPersonaId || IsLoading && loadedPersonaId is null && !waitingForPersona)
+ return;
+ waitingForPersona = false;
await Reload();
}
diff --git a/tests/e2e/Login/LoginTests.cs b/tests/e2e/Login/LoginTests.cs
index cb9ea49..f053e2f 100644
--- a/tests/e2e/Login/LoginTests.cs
+++ b/tests/e2e/Login/LoginTests.cs
@@ -34,11 +34,12 @@ namespace decePubClient.E2E.Login
await session.Page.Locator("nav [title='Switch persona']").First.ClickAsync();
await session.Page.Locator("nav").GetByRole(AriaRole.Button).Filter(new() { HasText = sibling.Name ?? sibling.UserName }).First.ClickAsync();
+ // the sibling's home, read with another token than the first persona's (whose own home may still be loading when the
+ // switch is asked for)
+ string FirstToken() => session.ApiCalls.FirstOrDefault(c => new Uri(c.Url).AbsolutePath.StartsWith("/api/") && c.Authorization is not null).Authorization;
Assert.True(await Pasture.Eventually(() => Task.FromResult(session.ApiCalls.Skip(before)
- .Any(c => new Uri(c.Url).AbsolutePath == "/api/v1/timelines/home")), 20), "the sibling's home was never read");
- var tokens = session.ApiCalls.Where(c => new Uri(c.Url).AbsolutePath.StartsWith("/api/") && c.Authorization is not null)
- .Select(c => c.Authorization).Distinct().ToList();
- Assert.True(tokens.Count >= 2, "both personas' requests went out with one token");
+ .Any(c => new Uri(c.Url).AbsolutePath == "/api/v1/timelines/home" && c.Authorization is not null && c.Authorization != FirstToken())), 20),
+ "the sibling's home was never read with its own token");
await session.AssertGuards();
}