fix(frontend): show a banner when LoginGate can't reach the backend

LoginGate's initial session check swallowed every failure into the
same "unauthenticated" branch, so a genuinely unreachable backend
looked identical to a normal logged-out state -- the one screen in
the app where "backend not here" showed no feedback at all, since
every banner-migrated component only renders after authentication.

api/client.ts's request() now throws a dedicated NetworkError (a
distinct type, not just a distinguishable message) for a fetch()
failure specifically, so LoginGate.tsx's catch can tell that apart
from a real 401 via instanceof and show a banner before falling
through to "unauthenticated" either way.

Verified with a real headless-browser run against the dev server
with no backend: the banner renders correctly and coexists with the
existing ?auth_error= banner without conflict.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-27 11:00:00 +02:00
parent 0e3295b746
commit fe344867c0
2 changed files with 26 additions and 9 deletions

View File

@@ -1,5 +1,5 @@
import { useEffect, useState } from "react";
import { api, BASE_URL } from "./api/client";
import { api, BASE_URL, NetworkError } from "./api/client";
import { showError } from "./banner";
import "./LoginGate.css";
import App from "./App";
@@ -34,7 +34,17 @@ export function LoginGate() {
setSession(s);
setStatus("authenticated");
})
.catch(() => setStatus("unauthenticated"));
.catch((e) => {
// A NetworkError here means the backend itself isn't reachable, not
// that this browser is genuinely logged out -- worth a banner, since
// otherwise this is the one place in the app where "backend not
// here" would show no feedback at all. Either way the screen still
// falls through to "unauthenticated" (showing the Log in button),
// since there's no session to trust regardless of why the check
// failed.
if (e instanceof NetworkError) showError(e.message);
setStatus("unauthenticated");
});
}, []);
// Keycloak redirects back here with ?auth_error=<code> when the