feat(14-04): CoverageBanner "manuell beobachten" denylist block

- Add DenylistedPortal type + fetchDenylistedPortals() to
  tender-radar-api.ts, following the existing credentials:'include' fetch
  convention
- CoverageBanner fetches the denylisted-portals endpoint on mount and
  renders vergabe24/aumass with direct links (rel="noopener noreferrer",
  target="_blank"); block renders independently of the onlyDoe coverage
  note and fails silently on fetch error
- Add CoverageBanner.test.tsx asserting both portal hrefs, independence
  from the coverage note, and fail-silent behavior

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-23 13:59:44 +02:00
parent 28c6c7fee1
commit 947325f6ad
3 changed files with 196 additions and 8 deletions
+29
View File
@@ -83,6 +83,21 @@ export interface CoverageResponse {
sources: Array<{ sourcePortal: string; count: number }>;
}
/**
* A single AGB-denylisted portal (UI-06/D-12) — vergabe24/aumass must be
* watched manually. `url` is the canonical direct-link, sourced server-side
* from `PORTAL_URLS` (source-registry.ts), never hardcoded here.
*/
export interface DenylistedPortal {
portal: string;
url: string;
}
/** Response shape of GET /modules/tender-radar/denylisted-portals (UI-06/D-12). */
export interface DenylistedPortalsResponse {
portals: DenylistedPortal[];
}
// --- API functions ---
/**
@@ -149,6 +164,20 @@ export async function fetchCoverage(): Promise<CoverageResponse> {
return res.json();
}
/**
* Fetch the AGB-denylisted portals (vergabe24, aumass) with their canonical
* direct-link URLs (UI-06/D-12) — feeds CoverageBanner's "manuell
* beobachten" block.
* GET /modules/tender-radar/denylisted-portals
*/
export async function fetchDenylistedPortals(): Promise<DenylistedPortalsResponse> {
const res = await fetch(`${API_URL}/modules/tender-radar/denylisted-portals`, {
credentials: 'include',
});
if (!res.ok) throw new Error('Failed to fetch denylisted portals');
return res.json();
}
/**
* Fetch a single tender's full detail (Plan 11-04, UI-02/D-07) for the
* `?tender=<id>` in-component detail view. `rawPayload` is 100% NULL in