Fix: Remove broken getKlausurApiUrl and clean up empty lines
Some checks failed
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-school (push) Successful in 42s
CI / test-go-edu-search (push) Successful in 34s
CI / test-python-klausur (push) Failing after 2m51s
CI / test-python-agent-core (push) Successful in 21s
CI / test-nodejs-website (push) Successful in 29s

sed replacement left orphaned hostname references in story page
and empty lines in getApiBase functions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-04-24 16:02:04 +02:00
parent b07f802c24
commit 9ba420fa91
150 changed files with 30231 additions and 32053 deletions

View File

@@ -0,0 +1,373 @@
'use client'
import React from 'react'
import {
REGULATIONS,
DOC_TYPES,
INDUSTRIES_LIST,
INDUSTRIES,
INDUSTRY_REGULATION_MAP,
TYPE_COLORS,
THEMATIC_GROUPS,
KEY_INTERSECTIONS,
RAG_DOCUMENTS,
isInRag,
} from '../rag-data'
import type { UseRAGPageReturn } from '../_hooks/useRAGPage'
import {
FutureOutlookSection,
RagCoverageSection,
FutureRegulationsSection,
LegalBasisSection,
} from './MapTabSections'
interface MapTabProps {
hook: UseRAGPageReturn
}
export function MapTab({ hook }: MapTabProps) {
const {
expandedRegulation,
setExpandedRegulation,
expandedDocTypes,
setExpandedDocTypes,
expandedMatrixDoc,
setExpandedMatrixDoc,
setActiveTab,
} = hook
return (
<div className="space-y-6">
{/* Industry Filter */}
<IndustryFilter
expandedRegulation={expandedRegulation}
setExpandedRegulation={setExpandedRegulation}
/>
{/* Thematic Groups */}
<ThematicGroupsSection setActiveTab={setActiveTab} setExpandedRegulation={setExpandedRegulation} />
{/* Key Intersections */}
<KeyIntersectionsSection />
{/* Regulation Matrix */}
<RegulationMatrix
expandedDocTypes={expandedDocTypes}
setExpandedDocTypes={setExpandedDocTypes}
expandedMatrixDoc={expandedMatrixDoc}
setExpandedMatrixDoc={setExpandedMatrixDoc}
/>
{/* Future Outlook Section */}
<FutureOutlookSection />
{/* RAG Coverage Overview */}
<RagCoverageSection />
{/* Potential Future Regulations */}
<FutureRegulationsSection />
{/* Legal Basis Info */}
<LegalBasisSection />
</div>
)
}
// --- Sub-components ---
function IndustryFilter({
expandedRegulation,
setExpandedRegulation,
}: {
expandedRegulation: string | null
setExpandedRegulation: (v: string | null) => void
}) {
return (
<div className="bg-white rounded-xl border border-slate-200 p-6">
<h3 className="font-semibold text-slate-900 mb-4">Regulierungen nach Branche</h3>
<p className="text-sm text-slate-500 mb-4">
Waehlen Sie Ihre Branche, um relevante Regulierungen zu sehen.
</p>
<div className="grid grid-cols-2 md:grid-cols-5 gap-3">
{INDUSTRIES.map((industry) => {
const regs = INDUSTRY_REGULATION_MAP[industry.id] || []
return (
<button
key={industry.id}
onClick={() => setExpandedRegulation(industry.id === expandedRegulation ? null : industry.id)}
className={`p-4 rounded-lg border text-left transition-all ${
expandedRegulation === industry.id
? 'border-teal-500 bg-teal-50 ring-2 ring-teal-200'
: 'border-slate-200 hover:border-slate-300 hover:bg-slate-50'
}`}
>
<div className="text-2xl mb-2">{industry.icon}</div>
<div className="font-medium text-slate-900 text-sm">{industry.name}</div>
<div className="text-xs text-slate-500 mt-1">{regs.length} Regulierungen</div>
</button>
)
})}
</div>
{/* Selected Industry Details */}
{expandedRegulation && INDUSTRIES.find(i => i.id === expandedRegulation) && (
<div className="mt-6 p-4 bg-slate-50 rounded-lg">
{(() => {
const industry = INDUSTRIES.find(i => i.id === expandedRegulation)!
const regCodes = INDUSTRY_REGULATION_MAP[industry.id] || []
const regs = REGULATIONS.filter(r => regCodes.includes(r.code))
return (
<>
<div className="flex items-center gap-3 mb-4">
<span className="text-3xl">{industry.icon}</span>
<div>
<h4 className="font-semibold text-slate-900">{industry.name}</h4>
<p className="text-sm text-slate-500">{industry.description}</p>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-3">
{regs.map((reg) => {
const regInRag = isInRag(reg.code)
return (
<div
key={reg.code}
className={`bg-white p-3 rounded-lg border ${regInRag ? 'border-green-200' : 'border-slate-200'}`}
>
<div className="flex items-center gap-2 mb-1">
<span className={`px-2 py-0.5 text-xs rounded ${TYPE_COLORS[reg.type]}`}>
{reg.code}
</span>
{regInRag ? (
<span className="px-1.5 py-0.5 text-[10px] font-bold bg-green-100 text-green-600 rounded">RAG</span>
) : (
<span className="px-1.5 py-0.5 text-[10px] font-bold bg-red-50 text-red-400 rounded"></span>
)}
</div>
<div className="font-medium text-sm text-slate-900">{reg.name}</div>
<div className="text-xs text-slate-500 mt-1 line-clamp-2">{reg.description}</div>
</div>
)
})}
</div>
</>
)
})()}
</div>
)}
</div>
)
}
function ThematicGroupsSection({
setActiveTab,
setExpandedRegulation,
}: {
setActiveTab: (v: any) => void
setExpandedRegulation: (v: string | null) => void
}) {
return (
<div className="bg-white rounded-xl border border-slate-200 p-6">
<h3 className="font-semibold text-slate-900 mb-4">Thematische Cluster</h3>
<p className="text-sm text-slate-500 mb-4">
Regulierungen gruppiert nach Themenbereichen - zeigt Ueberschneidungen.
</p>
<div className="space-y-4">
{THEMATIC_GROUPS.map((group) => (
<div key={group.id} className="border border-slate-200 rounded-lg overflow-hidden">
<div className={`${group.color} px-4 py-2 text-white font-medium flex items-center justify-between`}>
<span>{group.name}</span>
<span className="text-sm opacity-80">{group.regulations.length} Regulierungen</span>
</div>
<div className="p-4">
<p className="text-sm text-slate-600 mb-3">{group.description}</p>
<div className="flex flex-wrap gap-2">
{group.regulations.map((code) => {
const reg = REGULATIONS.find(r => r.code === code)
const codeInRag = isInRag(code)
return (
<span
key={code}
className={`px-3 py-1.5 rounded-full text-sm font-medium cursor-pointer ${
codeInRag
? 'bg-green-100 text-green-700 hover:bg-green-200'
: 'bg-slate-100 text-slate-700 hover:bg-slate-200'
}`}
onClick={() => {
setActiveTab('regulations')
setExpandedRegulation(code)
}}
title={`${reg?.fullName || code}${codeInRag ? ' (im RAG)' : ' (nicht im RAG)'}`}
>
{codeInRag ? '✓ ' : '✗ '}{code}
</span>
)
})}
</div>
</div>
</div>
))}
</div>
</div>
)
}
function KeyIntersectionsSection() {
return (
<div className="bg-white rounded-xl border border-slate-200 p-6">
<h3 className="font-semibold text-slate-900 mb-4">Wichtige Schnittstellen</h3>
<p className="text-sm text-slate-500 mb-4">
Bereiche, in denen sich mehrere Regulierungen ueberschneiden und zusammenwirken.
</p>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{KEY_INTERSECTIONS.map((intersection, idx) => (
<div key={idx} className="bg-gradient-to-br from-slate-50 to-slate-100 rounded-lg p-4 border border-slate-200">
<div className="flex flex-wrap gap-1 mb-2">
{intersection.regulations.map((code) => (
<span
key={code}
className={`px-2 py-0.5 text-xs font-medium rounded ${
isInRag(code)
? 'bg-green-100 text-green-700'
: 'bg-red-50 text-red-500'
}`}
>
{isInRag(code) ? '✓ ' : '✗ '}{code}
</span>
))}
</div>
<div className="font-medium text-slate-900 text-sm mb-1">{intersection.topic}</div>
<div className="text-xs text-slate-500">{intersection.description}</div>
</div>
))}
</div>
</div>
)
}
function RegulationMatrix({
expandedDocTypes,
setExpandedDocTypes,
expandedMatrixDoc,
setExpandedMatrixDoc,
}: {
expandedDocTypes: string[]
setExpandedDocTypes: (fn: (prev: string[]) => string[]) => void
expandedMatrixDoc: string | null
setExpandedMatrixDoc: (v: string | null) => void
}) {
return (
<div className="bg-white rounded-xl border border-slate-200 overflow-hidden">
<div className="px-4 py-3 border-b bg-slate-50">
<h3 className="font-semibold text-slate-900">Branchen-Regulierungs-Matrix</h3>
<p className="text-sm text-slate-500">{RAG_DOCUMENTS.length} Dokumente in {DOC_TYPES.length} Kategorien</p>
</div>
<div className="overflow-x-auto">
<table className="w-full text-xs">
<thead className="bg-slate-50 border-b sticky top-0 z-10">
<tr>
<th className="px-2 py-2 text-left font-medium text-slate-500 sticky left-0 bg-slate-50 min-w-[200px]">Regulierung</th>
{INDUSTRIES_LIST.filter((i: any) => i.id !== 'all').map((industry: any) => (
<th key={industry.id} className="px-2 py-2 text-center font-medium text-slate-500 min-w-[60px]">
<div className="flex flex-col items-center">
<span className="text-lg">{industry.icon}</span>
<span className="text-[10px] leading-tight">{industry.name.split('/')[0]}</span>
</div>
</th>
))}
</tr>
</thead>
<tbody>
{DOC_TYPES.map((docType: any) => {
const docsInType = RAG_DOCUMENTS.filter((d: any) => d.doc_type === docType.id)
if (docsInType.length === 0) return null
const isExpanded = expandedDocTypes.includes(docType.id)
return (
<React.Fragment key={docType.id}>
<tr
className="bg-slate-100 border-t-2 border-slate-300 cursor-pointer hover:bg-slate-200"
onClick={() => {
setExpandedDocTypes(prev =>
prev.includes(docType.id)
? prev.filter((id: string) => id !== docType.id)
: [...prev, docType.id]
)
}}
>
<td colSpan={INDUSTRIES_LIST.length} className="px-3 py-2 font-bold text-slate-700">
<span className="mr-2">{isExpanded ? '\u25BC' : '\u25B6'}</span>
{docType.icon} {docType.label} ({docsInType.length})
</td>
</tr>
{isExpanded && docsInType.map((doc: any) => (
<React.Fragment key={doc.code}>
<tr
className={`hover:bg-slate-50 border-b border-slate-100 cursor-pointer ${expandedMatrixDoc === doc.code ? 'bg-teal-50' : ''}`}
onClick={() => setExpandedMatrixDoc(expandedMatrixDoc === doc.code ? null : doc.code)}
>
<td className="px-2 py-1.5 font-medium sticky left-0 bg-white">
<span className="flex items-center gap-1">
{isInRag(doc.code) ? (
<span className="text-green-500 text-[10px]"></span>
) : (
<span className="text-red-300 text-[10px]"></span>
)}
<span className="text-teal-600 truncate max-w-[180px]" title={doc.full_name || doc.name}>
{doc.name}
</span>
{(doc.applicability_note || doc.description) && (
<span className="text-slate-400 text-[10px] ml-1">{expandedMatrixDoc === doc.code ? '▼' : 'ⓘ'}</span>
)}
</span>
</td>
{INDUSTRIES_LIST.filter((i: any) => i.id !== 'all').map((industry: any) => {
const applies = doc.industries.includes(industry.id) || doc.industries.includes('all')
return (
<td key={industry.id} className="px-2 py-1.5 text-center">
{applies ? (
<span className="inline-flex items-center justify-center w-5 h-5 bg-teal-100 text-teal-600 rounded-full"></span>
) : (
<span className="inline-flex items-center justify-center w-5 h-5 text-slate-300"></span>
)}
</td>
)
})}
</tr>
{expandedMatrixDoc === doc.code && (doc.applicability_note || doc.description) && (
<tr className="bg-teal-50 border-b border-teal-200">
<td colSpan={INDUSTRIES_LIST.length} className="px-4 py-3">
<div className="text-xs space-y-1.5">
{doc.full_name && (
<p className="font-semibold text-slate-700">{doc.full_name}</p>
)}
{doc.applicability_note && (
<p className="text-teal-700 bg-teal-100 px-2 py-1 rounded inline-block">
<span className="font-medium">Branchenrelevanz:</span> {doc.applicability_note}
</p>
)}
{doc.description && (
<p className="text-slate-600">{doc.description}</p>
)}
{doc.effective_date && (
<p className="text-slate-400">In Kraft: {doc.effective_date}</p>
)}
</div>
</td>
</tr>
)}
</React.Fragment>
))}
</React.Fragment>
)
})}
</tbody>
</table>
</div>
</div>
)
}
// FutureOutlookSection, RagCoverageSection, FutureRegulationsSection,
// LegalBasisSection are imported from ./MapTabSections.tsx