'use client' import React, { useMemo, useState, useRef, useEffect } from 'react' import { SearchInput, FilterDropdown, Pagination, ExpandableRow } from './LibraryTable' export interface HazardPattern { id: string name_de: string name_en: string priority: number required_component_tags: string[] generated_hazard_categories: string[] scenario_de: string trigger_de: string harm_de: string affected_de?: string zone_de?: string } const PER_PAGE = 50 const PRIORITY_OPTIONS = [ { value: '', label: 'Alle Prioritaeten' }, { value: '90', label: 'Prioritaet > 90' }, { value: '70', label: 'Prioritaet > 70' }, { value: '50', label: 'Prioritaet > 50' }, ] function priorityColor(p: number): string { if (p >= 90) return 'bg-red-100 text-red-800' if (p >= 70) return 'bg-orange-100 text-orange-800' if (p >= 50) return 'bg-yellow-100 text-yellow-800' return 'bg-gray-100 text-gray-700' } interface Props { patterns: HazardPattern[] } export default function PatternsTab({ patterns }: Props) { const [search, setSearch] = useState('') const [debounced, setDebounced] = useState('') const [catFilter, setCatFilter] = useState('') const [prioFilter, setPrioFilter] = useState('') const [page, setPage] = useState(1) const timer = useRef | null>(null) useEffect(() => { timer.current = setTimeout(() => setDebounced(search), 300) return () => { if (timer.current) clearTimeout(timer.current) } }, [search]) useEffect(() => { setPage(1) }, [debounced, catFilter, prioFilter]) const categories = useMemo(() => { const set = new Set() patterns.forEach((p) => p.generated_hazard_categories.forEach((c) => set.add(c))) return Array.from(set).sort() }, [patterns]) const catOptions = useMemo(() => [ { value: '', label: 'Alle Kategorien' }, ...categories.map((c) => ({ value: c, label: c.replace(/_/g, ' ') })), ], [categories]) const filtered = useMemo(() => { const q = debounced.toLowerCase() const prioMin = prioFilter ? parseInt(prioFilter) : 0 return patterns.filter((p) => { if (q && !p.name_de.toLowerCase().includes(q) && !p.scenario_de.toLowerCase().includes(q) && !p.harm_de.toLowerCase().includes(q)) return false if (catFilter && !p.generated_hazard_categories.includes(catFilter)) return false if (prioMin && p.priority <= prioMin) return false return true }) }, [patterns, debounced, catFilter, prioFilter]) const totalPages = Math.ceil(filtered.length / PER_PAGE) const pageItems = filtered.slice((page - 1) * PER_PAGE, page * PER_PAGE) return (
{patterns.length} Patterns{filtered.length !== patterns.length && ` (${filtered.length} gefiltert)`}
{['ID', 'Name', 'Kategorie', 'Prioritaet', 'Schaden', 'Tags'].map((h) => ( ))} {pageItems.map((p) => ( {p.id.slice(0, 8)}, {p.name_de}, {p.generated_hazard_categories[0]?.replace(/_/g, ' ') || '-'}, {p.priority}, {p.harm_de || '-'}, {p.required_component_tags.length > 0 ? p.required_component_tags.slice(0, 2).join(', ') : '-'}{p.required_component_tags.length > 2 ? ` +${p.required_component_tags.length - 2}` : ''}, ]} expandedContent={
{p.scenario_de &&
Szenario: {p.scenario_de}
} {p.trigger_de &&
Ausloeser: {p.trigger_de}
} {p.harm_de &&
Schaden: {p.harm_de}
} {p.affected_de &&
Betroffene: {p.affected_de}
} {p.zone_de &&
Zone: {p.zone_de}
} {p.generated_hazard_categories.length > 0 && (
{p.generated_hazard_categories.map((c) => ( {c.replace(/_/g, ' ')} ))}
)}
} /> ))} {pageItems.length === 0 && (
)}
{h}
Keine Patterns gefunden
) }