'use client'; import { Suspense } from 'react'; import { useRouter, useSearchParams } from 'next/navigation'; import { CoverageBanner } from './components/CoverageBanner'; import { FilterPanel } from './components/FilterPanel'; import { ResultsList } from './components/ResultsList'; import { TenderDetail } from './components/TenderDetail'; /** * Ausschreibungs-Radar module page within the portal. * * Replaces the Phase 10 placeholder (CONFIG-01 MVP stub) with the real * Trefferliste (Plan 11-01): CoverageBanner explains data coverage, * FilterPanel writes filter/sort state into the URL, ResultsList reads it * and renders the ~1671 existing DÖE tenders. * * Plan 11-04 (UI-02, D-07): the `?tender=` URL param drives an * in-component detail view (TenderDetail) rendered as an overlay on top * of the list — deliberately NOT a separate Next.js sub-route, since this * page is mounted via `dynamic(..., { ssr: false })` under * `[category]/[moduleSlug]` (Anti-Pattern/Assumption A5). A row click in * ResultsList sets the param; closing the detail removes it. * * `useSearchParams()` (used by FilterPanel/ResultsList/this component) * requires a Suspense boundary per the Next.js App Router contract — * wrapped here even though this component is loaded via * `dynamic(..., { ssr: false })` (module-loader.ts), per the plan's * explicit Next 16 guidance. * * Intentional hardcoded German strings: full i18n (next-intl message * keys) is CONFIG-03, planned for Phase 14 (Research Open Question 3, * RESOLVED). */ function TenderRadarContent() { const router = useRouter(); const searchParams = useSearchParams(); const tenderId = searchParams.get('tender'); const closeDetail = () => { const next = new URLSearchParams(searchParams.toString()); next.delete('tender'); router.replace(`?${next.toString()}`); }; return (

Ausschreibungs-Radar

{tenderId && }
); } export default function TenderRadarPage() { return (

Lädt…

} >
); }