fix(web): show an outage as an outage, and drop superseded fetches

The home page caught every fetch failure and rendered its empty state,
so a backend outage looked like a site with no schools in it. School
pages turned any error into notFound(), which told visitors — and
crawlers — that a real school had ceased to exist. Place fetches did the
same by returning [] and null. Failures now reach a retryable error
boundary; only a genuine 404 still calls notFound().

"Load more" and the map fetch resolved against whatever state existed
when they returned, so results from an abandoned search appended
themselves to the new ones. Each fetch now carries an AbortController
and checks that its search scope is still current before touching state.
The map only records its cache key on success, so a failed load retries
instead of pinning the stale marker set.

Jest ignored .next/, whose build output otherwise shadowed real suites.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
TudorandClaude Opus 5 committed 2026-09-15 10:17:18 +01:00
1 parent 9b75f54206
commit 7b41218e6e
8 files changed
+231 -80

No files matched your search

+5 -2
View File
@@ -1,3 +1,5 @@
import { APIFetchError } from './api';
/**
* Client for the places API.
*
@@ -69,7 +71,7 @@ const API = process.env.FASTAPI_URL || process.env.NEXT_PUBLIC_API_URL
export async function fetchPlaces(): Promise<PlaceSummary[]> {
const res = await fetch(`${API}/places`, { next: { revalidate: 604800 } });
if (!res.ok) return [];
if (!res.ok) throw new APIFetchError("Unable to load places", res.status);
return (await res.json()).places ?? [];
}
@@ -79,6 +81,7 @@ export async function fetchPlace(
const q = phase ? `?phase=${encodeURIComponent(phase)}` : '';
const res = await fetch(`${API}/places/${kind}/${slug}${q}`,
{ next: { revalidate: 604800 } });
if (!res.ok) return null;
if (res.status === 404) return null;
if (!res.ok) throw new APIFetchError("Unable to load place", res.status);
return res.json();
}