feat(iace): add withdrawn filter to norms library frontend

- Add withdrawn/valid_until/replaced_by to Norm interface
- Add Status filter (Aktiv/Zurueckgezogen) — defaults to "Aktiv"
- Withdrawn norms hidden by default, viewable via filter

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-05-09 08:50:26 +02:00
parent 4bfb438c92
commit 4d708b4443
@@ -15,6 +15,9 @@ export interface Norm {
mandatory: boolean mandatory: boolean
relevant_sections: string[] relevant_sections: string[]
beuth_url: string beuth_url: string
withdrawn?: boolean
valid_until?: string
replaced_by?: string
} }
const PER_PAGE = 50 const PER_PAGE = 50
@@ -30,6 +33,11 @@ const MANDATORY_OPTIONS = [
{ value: 'ja', label: 'Pflicht: Ja' }, { value: 'ja', label: 'Pflicht: Ja' },
{ value: 'nein', label: 'Pflicht: Nein' }, { value: 'nein', label: 'Pflicht: Nein' },
] ]
const STATUS_OPTIONS = [
{ value: '', label: 'Status: Alle' },
{ value: 'active', label: 'Aktiv' },
{ value: 'withdrawn', label: 'Zurueckgezogen' },
]
interface Props { norms: Norm[] } interface Props { norms: Norm[] }
@@ -38,6 +46,7 @@ export default function NormenTab({ norms }: Props) {
const [debounced, setDebounced] = useState('') const [debounced, setDebounced] = useState('')
const [typeFilter, setTypeFilter] = useState('') const [typeFilter, setTypeFilter] = useState('')
const [mandatoryFilter, setMandatoryFilter] = useState('') const [mandatoryFilter, setMandatoryFilter] = useState('')
const [statusFilter, setStatusFilter] = useState('active')
const [page, setPage] = useState(1) const [page, setPage] = useState(1)
const timer = useRef<ReturnType<typeof setTimeout> | null>(null) const timer = useRef<ReturnType<typeof setTimeout> | null>(null)
@@ -46,7 +55,7 @@ export default function NormenTab({ norms }: Props) {
return () => { if (timer.current) clearTimeout(timer.current) } return () => { if (timer.current) clearTimeout(timer.current) }
}, [search]) }, [search])
useEffect(() => { setPage(1) }, [debounced, typeFilter, mandatoryFilter]) useEffect(() => { setPage(1) }, [debounced, typeFilter, mandatoryFilter, statusFilter])
const filtered = useMemo(() => { const filtered = useMemo(() => {
const q = debounced.toLowerCase() const q = debounced.toLowerCase()
@@ -55,9 +64,11 @@ export default function NormenTab({ norms }: Props) {
if (typeFilter && n.norm_type !== typeFilter) return false if (typeFilter && n.norm_type !== typeFilter) return false
if (mandatoryFilter === 'ja' && !n.mandatory) return false if (mandatoryFilter === 'ja' && !n.mandatory) return false
if (mandatoryFilter === 'nein' && n.mandatory) return false if (mandatoryFilter === 'nein' && n.mandatory) return false
if (statusFilter === 'active' && n.withdrawn) return false
if (statusFilter === 'withdrawn' && !n.withdrawn) return false
return true return true
}) })
}, [norms, debounced, typeFilter, mandatoryFilter]) }, [norms, debounced, typeFilter, mandatoryFilter, statusFilter])
const totalPages = Math.ceil(filtered.length / PER_PAGE) const totalPages = Math.ceil(filtered.length / PER_PAGE)
const pageItems = filtered.slice((page - 1) * PER_PAGE, page * PER_PAGE) const pageItems = filtered.slice((page - 1) * PER_PAGE, page * PER_PAGE)
@@ -70,6 +81,7 @@ export default function NormenTab({ norms }: Props) {
</div> </div>
<FilterDropdown label="Normtyp" value={typeFilter} options={TYPE_OPTIONS} onChange={setTypeFilter} /> <FilterDropdown label="Normtyp" value={typeFilter} options={TYPE_OPTIONS} onChange={setTypeFilter} />
<FilterDropdown label="Pflicht" value={mandatoryFilter} options={MANDATORY_OPTIONS} onChange={setMandatoryFilter} /> <FilterDropdown label="Pflicht" value={mandatoryFilter} options={MANDATORY_OPTIONS} onChange={setMandatoryFilter} />
<FilterDropdown label="Status" value={statusFilter} options={STATUS_OPTIONS} onChange={setStatusFilter} />
<span className="text-sm text-gray-500 dark:text-gray-400 ml-auto"> <span className="text-sm text-gray-500 dark:text-gray-400 ml-auto">
{norms.length} Normen{filtered.length !== norms.length && ` (${filtered.length} gefiltert)`} {norms.length} Normen{filtered.length !== norms.length && ` (${filtered.length} gefiltert)`}
</span> </span>