'use client' import { useState, useEffect, useRef, useCallback } from 'react' import { useTheme } from '@/lib/ThemeContext' interface SchoolSearchProps { city: string bundesland: string bundeslandName: string selectedSchool: string onSelectSchool: (schoolName: string, schoolId?: string) => void className?: string } interface SchoolSuggestion { id: string name: string type: string address?: string city?: string source: 'api' | 'mock' } // Edu-Search API URL - uses HTTPS proxy on port 8089 (edu-search runs on 8088) const getApiUrl = () => { if (typeof window === 'undefined') return 'http://localhost:8088' const { hostname, protocol } = window.location // localhost: direct HTTP to 8088, macmini: HTTPS via nginx proxy on 8089 return hostname === 'localhost' ? 'http://localhost:8088' : `${protocol}//${hostname}:8089` } // Attribution data for Open Data sources by Bundesland (CTRL-SRC-001) const BUNDESLAND_ATTRIBUTION: Record = { BW: { source: 'Open Data Baden-Wuerttemberg', license: 'DL-DE-BY-2.0', licenseUrl: 'https://www.govdata.de/dl-de/by-2-0' }, BY: { source: 'Open Data Bayern', license: 'DL-DE-BY-2.0', licenseUrl: 'https://www.govdata.de/dl-de/by-2-0' }, BE: { source: 'Datenportal Berlin', license: 'CC-BY', licenseUrl: 'https://creativecommons.org/licenses/by/4.0/' }, BB: { source: 'Daten Brandenburg', license: 'DL-DE-BY-2.0', licenseUrl: 'https://www.govdata.de/dl-de/by-2-0' }, HB: { source: 'Open Data Bremen', license: 'CC-BY', licenseUrl: 'https://creativecommons.org/licenses/by/4.0/' }, HH: { source: 'Transparenzportal Hamburg', license: 'DL-DE-BY-2.0', licenseUrl: 'https://www.govdata.de/dl-de/by-2-0' }, HE: { source: 'Open Data Hessen', license: 'DL-DE-BY-2.0', licenseUrl: 'https://www.govdata.de/dl-de/by-2-0' }, MV: { source: 'Open Data MV', license: 'DL-DE-BY-2.0', licenseUrl: 'https://www.govdata.de/dl-de/by-2-0' }, NI: { source: 'Open Data Niedersachsen', license: 'DL-DE-BY-2.0', licenseUrl: 'https://www.govdata.de/dl-de/by-2-0' }, NW: { source: 'Open.NRW', license: 'DL-DE-BY-2.0', licenseUrl: 'https://www.govdata.de/dl-de/by-2-0' }, RP: { source: 'Open Data Rheinland-Pfalz', license: 'DL-DE-BY-2.0', licenseUrl: 'https://www.govdata.de/dl-de/by-2-0' }, SL: { source: 'Open Data Saarland', license: 'DL-DE-BY-2.0', licenseUrl: 'https://www.govdata.de/dl-de/by-2-0' }, SN: { source: 'Datenportal Sachsen', license: 'DL-DE-BY-2.0', licenseUrl: 'https://www.govdata.de/dl-de/by-2-0' }, ST: { source: 'Open Data Sachsen-Anhalt', license: 'DL-DE-BY-2.0', licenseUrl: 'https://www.govdata.de/dl-de/by-2-0' }, SH: { source: 'Open Data Schleswig-Holstein', license: 'DL-DE-BY-2.0', licenseUrl: 'https://www.govdata.de/dl-de/by-2-0' }, TH: { source: 'Open Data Thueringen', license: 'DL-DE-BY-2.0', licenseUrl: 'https://www.govdata.de/dl-de/by-2-0' }, } // Category to display type mapping const getCategoryDisplayType = (category?: string): string => { switch (category) { case 'primary': return 'Grundschule' case 'secondary': return 'Sekundarschule' case 'vocational': return 'Berufsschule' case 'special': return 'Foerderschule' default: return 'Schule' } } export function SchoolSearch({ city, bundesland, bundeslandName, selectedSchool, onSelectSchool, className = '' }: SchoolSearchProps) { const { isDark } = useTheme() const [searchQuery, setSearchQuery] = useState(selectedSchool || '') const [suggestions, setSuggestions] = useState([]) const [isSearching, setIsSearching] = useState(false) const [showSuggestions, setShowSuggestions] = useState(false) const searchTimeoutRef = useRef(null) const containerRef = useRef(null) // Suche nach Schulen (echte API) const searchSchools = useCallback(async (query: string) => { if (query.length < 2) { setSuggestions([]) return } setIsSearching(true) try { // Real API call to edu-search-service const params = new URLSearchParams({ q: query, limit: '10', }) if (city) params.append('city', city) if (bundesland) params.append('state', bundesland) const response = await fetch(`${getApiUrl()}/api/v1/schools/search?${params}`) if (response.ok) { const data = await response.json() const apiSchools: SchoolSuggestion[] = (data.schools || []).map((school: { id: string name: string school_type_name?: string school_category?: string street?: string city?: string postal_code?: string }) => ({ id: school.id, name: school.name, type: school.school_type_name || getCategoryDisplayType(school.school_category), address: school.street ? `${school.street}, ${school.postal_code || ''} ${school.city || ''}`.trim() : undefined, city: school.city, source: 'api' as const, })) setSuggestions(apiSchools) } else { console.error('School search API error:', response.status) setSuggestions([]) } } catch (error) { console.error('School search error:', error) setSuggestions([]) } finally { setIsSearching(false) } }, [city, bundesland]) // Debounced Search useEffect(() => { if (searchTimeoutRef.current) { clearTimeout(searchTimeoutRef.current) } searchTimeoutRef.current = setTimeout(() => { searchSchools(searchQuery) }, 300) return () => { if (searchTimeoutRef.current) { clearTimeout(searchTimeoutRef.current) } } }, [searchQuery, searchSchools]) // Klick ausserhalb schließt Dropdown useEffect(() => { const handleClickOutside = (event: MouseEvent) => { if (containerRef.current && !containerRef.current.contains(event.target as Node)) { setShowSuggestions(false) } } document.addEventListener('mousedown', handleClickOutside) return () => document.removeEventListener('mousedown', handleClickOutside) }, []) // Schule auswaehlen const handleSelectSchool = (school: SchoolSuggestion) => { setSearchQuery(school.name) onSelectSchool(school.name, school.id) setSuggestions([]) setShowSuggestions(false) } // Manuelle Eingabe bestaetigen const handleManualInput = () => { if (searchQuery.trim()) { onSelectSchool(searchQuery.trim()) setShowSuggestions(false) } } // Schultyp-Icon const getSchoolTypeIcon = (type: string) => { switch (type.toLowerCase()) { case 'gymnasium': return 'πŸŽ“' case 'gesamtschule': case 'stadtteilschule': return '🏫' case 'realschule': return 'πŸ“š' case 'hauptschule': case 'mittelschule': return 'πŸ“–' case 'grundschule': return '🏠' case 'berufsschule': return 'πŸ”§' case 'foerderschule': return '🀝' case 'privatschule': return '🏰' case 'waldorfschule': return '🌿' default: return '🏫' } } return (
{/* Suchfeld */}
{ setSearchQuery(e.target.value) setShowSuggestions(true) }} onFocus={() => setShowSuggestions(true)} onKeyDown={(e) => { if (e.key === 'Enter') { handleManualInput() } }} placeholder={`Schule in ${city} suchen...`} className={`w-full px-6 py-4 pl-14 text-lg rounded-2xl border transition-all ${ isDark ? 'bg-white/10 border-white/20 text-white placeholder-white/40 focus:border-blue-400' : 'bg-white border-slate-300 text-slate-900 placeholder-slate-400 focus:border-blue-500' } focus:outline-none focus:ring-2 focus:ring-blue-500/30`} autoFocus /> {isSearching && (
)}
{/* Vorschlaege Dropdown */} {showSuggestions && suggestions.length > 0 && (
{suggestions.map((school, index) => ( ))} {/* Attribution Footer (CTRL-SRC-001) */} {(() => { const attr = BUNDESLAND_ATTRIBUTION[bundesland] return attr ? (
Quelle: {attr.source} β€’ e.stopPropagation()} > {attr.license}
) : null })()}
)} {/* Keine Ergebnisse Info */} {showSuggestions && searchQuery.length >= 2 && suggestions.length === 0 && !isSearching && (

Keine Schulen gefunden. Tippen Sie den Namen ein und druecken Sie Enter.

)}
{/* Standort Info */}
πŸ“

{city}, {bundeslandName}

Ihr Standort

{/* Hinweis */}

Waehlen Sie aus den Vorschlaegen oder geben Sie den Namen manuell ein

) }